use crate::models::{NewApiResponse, NewApiBulletin, Bulletin, NewApiEventsResponse, NewApiEvent, Event, EventType, ConferenceDataResponse, ConferenceData, ScheduleResponse, PersonnelData, LoginRequest, LoginResponse};
use anyhow::{anyhow, Result};
use reqwest::Client;
use chrono::{NaiveDate, DateTime, Utc};

pub struct NewApiClient {
    client: Client,
    base_url: String,
    auth_token: Option<String>,
}

impl NewApiClient {
    pub fn new() -> Self {
        Self {
            client: Client::new(),
            base_url: "https://api.rockvilletollandsda.church".to_string(),
            auth_token: None,
        }
    }

    pub fn with_auth_token(mut self, token: String) -> Self {
        self.auth_token = Some(token);
        self
    }

    pub async fn login(mut self, username: String, password: String) -> Result<Self> {
        let url = format!("{}/api/auth/login", self.base_url);
        let login_request = LoginRequest { username, password };
        
        let response = self.client
            .post(&url)
            .json(&login_request)
            .send()
            .await?;

        if !response.status().is_success() {
            let error_text = response.text().await?;
            return Err(anyhow!("Failed to login: {}", error_text));
        }

        let login_response: LoginResponse = response.json().await?;
        
        if !login_response.success {
            return Err(anyhow!("Login failed: {:?}", login_response.message));
        }

        let data = login_response.data
            .ok_or_else(|| anyhow!("No data received from login"))?;
        let token = data.token;
        
        self.auth_token = Some(token);
        Ok(self)
    }

    pub async fn get_current_bulletin(&self) -> Result<NewApiBulletin> {
        let url = format!("{}/api/bulletins/next", self.base_url);
        
        let response = self.client
            .get(&url)
            .send()
            .await?;

        if !response.status().is_success() {
            let error_text = response.text().await?;
            return Err(anyhow!("Failed to get next bulletin: {}", error_text));
        }

        let api_response: NewApiResponse = response.json().await?;
        
        if !api_response.success {
            return Err(anyhow!("API returned error: {:?}", api_response.message));
        }

        Ok(api_response.data)
    }

    pub async fn get_current_bulletin_as_bulletin(&self) -> Result<Bulletin> {
        let new_bulletin = self.get_current_bulletin().await?;
        Ok(convert_to_bulletin(new_bulletin)?)
    }

    pub async fn get_upcoming_events(&self) -> Result<Vec<NewApiEvent>> {
        let url = format!("{}/api/events/upcoming", self.base_url);
        
        let response = self.client
            .get(&url)
            .send()
            .await?;

        if !response.status().is_success() {
            let error_text = response.text().await?;
            return Err(anyhow!("Failed to get upcoming events: {}", error_text));
        }

        let api_response: NewApiEventsResponse = response.json().await?;
        
        if !api_response.success {
            return Err(anyhow!("API returned error: {:?}", api_response.message));
        }

        Ok(api_response.data)
    }

    pub async fn get_upcoming_events_as_events(&self) -> Result<Vec<Event>> {
        let new_events = self.get_upcoming_events().await?;
        Ok(new_events.into_iter().map(convert_to_event).collect::<Result<Vec<_>>>()?)
    }

    pub async fn create_bulletin(&self, bulletin: &NewApiBulletin) -> Result<NewApiBulletin> {
        let url = format!("{}/api/admin/bulletins", self.base_url);
        
        let mut request = self.client.post(&url).json(bulletin);
        
        if let Some(ref token) = self.auth_token {
            request = request.header("Authorization", format!("Bearer {}", token));
        }
        
        let response = request.send().await?;

        if !response.status().is_success() {
            let error_text = response.text().await?;
            return Err(anyhow!("Failed to create bulletin: {}", error_text));
        }

        let api_response: NewApiResponse = response.json().await?;
        
        if !api_response.success {
            return Err(anyhow!("API returned error: {:?}", api_response.message));
        }

        Ok(api_response.data)
    }

    pub async fn create_bulletin_from_bulletin(&self, bulletin: &Bulletin) -> Result<NewApiBulletin> {
        let conference_data = self.get_conference_data(bulletin.date).await?;
        let sunset_text = format!(
            "Sunset Tonight: {}\n\nSunset Next Friday: {}",
            conference_data.sunset_tonight,
            conference_data.sunset_next_friday
        );
        let new_bulletin = convert_from_bulletin(bulletin.clone(), sunset_text)?;
        self.create_bulletin(&new_bulletin).await
    }

    pub async fn upload_pdf(&self, bulletin_id: &str, pdf_path: &std::path::Path) -> Result<String> {
        let url = format!("{}/api/upload/bulletins/{}/pdf", self.base_url, bulletin_id);
        
        let file = tokio::fs::read(pdf_path).await?;
        let file_name = pdf_path.file_name()
            .ok_or_else(|| anyhow!("Invalid file path"))?
            .to_string_lossy()
            .to_string();
        
        let part = reqwest::multipart::Part::bytes(file)
            .file_name(file_name)
            .mime_str("application/pdf")?;
        
        println!("Debug: Sending bulletin_id: '{}'", bulletin_id);
        println!("Debug: Upload URL: {}", url);
        
        let form = reqwest::multipart::Form::new()
            .part("file", part);
        
        let mut request = self.client.post(&url).multipart(form);
        
        if let Some(ref token) = self.auth_token {
            request = request.header("Authorization", format!("Bearer {}", token));
        }
        
        let response = request.send().await?;

        let status = response.status();
        let response_text = response.text().await?;
        
        if !status.is_success() {
            return Err(anyhow!("Failed to upload PDF (HTTP {}): {}", status, response_text));
        }

        Ok(response_text)
    }

    pub async fn get_conference_data(&self, date: NaiveDate) -> Result<ConferenceData> {
        let date_str = date.format("%Y-%m-%d").to_string();
        let url = format!("{}/api/conference-data?date={}", self.base_url, date_str);
        
        let response = self.client
            .get(&url)
            .send()
            .await?;

        if !response.status().is_success() {
            let error_text = response.text().await?;
            return Err(anyhow!("Failed to get conference data: {}", error_text));
        }

        let api_response: ConferenceDataResponse = response.json().await?;
        
        if !api_response.success {
            return Err(anyhow!("API returned error: {:?}", api_response.message));
        }

        Ok(api_response.data)
    }

    pub async fn get_schedule_data(&self, date: NaiveDate) -> Result<PersonnelData> {
        let date_str = date.format("%Y-%m-%d").to_string();
        let url = format!("{}/api/schedule?date={}", self.base_url, date_str);
        
        let response = self.client
            .get(&url)
            .send()
            .await?;

        if !response.status().is_success() {
            let error_text = response.text().await?;
            return Err(anyhow!("Failed to get schedule data: {}", error_text));
        }

        let api_response: ScheduleResponse = response.json().await?;
        
        if !api_response.success {
            return Err(anyhow!("API returned error: {:?}", api_response.message));
        }

        Ok(api_response.data.personnel)
    }
}

pub fn convert_to_bulletin(new_bulletin: NewApiBulletin) -> Result<Bulletin> {
    let date = NaiveDate::parse_from_str(&new_bulletin.date, "%Y-%m-%d")
        .map_err(|e| anyhow!("Failed to parse date: {}", e))?;
    
    Ok(Bulletin {
        id: Some(new_bulletin.id),
        date,
        sermon_title: new_bulletin.title,
        sermon_scripture: new_bulletin.scripture_reading,
        sermon_preacher: "Pastor Joseph Piresson".to_string(), // Default from API response
        sermon_opening_hymn: "".to_string(), // Not available in new API
        sermon_closing_hymn: "".to_string(), // Not available in new API
        sabbath_school_section: new_bulletin.sabbath_school,
        divine_worship_section: new_bulletin.divine_worship,
        pdf: new_bulletin.pdf_file,
        cover_image: new_bulletin.cover_image,
        created: None,
        updated: None,
    })
}

fn convert_to_event(new_event: NewApiEvent) -> Result<Event> {
    // Parse the start_time to extract date
    let start_datetime = DateTime::parse_from_rfc3339(&new_event.start_time)
        .map_err(|e| anyhow!("Failed to parse start_time: {}", e))?;
    let date = start_datetime.date_naive();
    
    // Extract time from start_time
    let time = start_datetime.format("%I:%M %p").to_string();
    
    // Parse end_time
    let end_datetime = DateTime::parse_from_rfc3339(&new_event.end_time)
        .map_err(|e| anyhow!("Failed to parse end_time: {}", e))?;
    let end_time = Some(end_datetime.format("%I:%M %p").to_string());
    
    // Determine event type based on category
    let event_type = match new_event.category.as_str() {
        "Service" => EventType::Event,
        _ => EventType::Announcement,
    };
    
    Ok(Event {
        id: Some(new_event.id),
        name: new_event.title,
        date,
        time,
        end_time,
        description: Some(new_event.description),
        location: Some(new_event.location),
        event_type,
        start_datetime: Some(start_datetime.with_timezone(&Utc)),
        end_datetime: Some(end_datetime.with_timezone(&Utc)),
        recurring_type: new_event.recurring_type,
        created: None,
        updated: None,
    })
}

fn convert_from_bulletin(bulletin: Bulletin, sunset_text: String) -> Result<NewApiBulletin> {
    Ok(NewApiBulletin {
        id: bulletin.id.unwrap_or_else(|| uuid::Uuid::new_v4().to_string()),
        title: bulletin.sermon_title,
        date: bulletin.date.format("%Y-%m-%d").to_string(),
        url: Some("".to_string()),
        cover_image_path: None,
        pdf_url: Some("".to_string()),
        is_active: true,
        pdf_file: bulletin.pdf,
        sabbath_school: bulletin.sabbath_school_section,
        divine_worship: bulletin.divine_worship_section,
        scripture_reading: bulletin.sermon_scripture,
        sunset: Some(sunset_text),
        cover_image: bulletin.cover_image,
        pdf_path: Some("".to_string()),
        created_at: chrono::Utc::now().to_rfc3339(),
        updated_at: chrono::Utc::now().to_rfc3339(),
    })
}