use crate::models::*;
use anyhow::Result;
use reqwest::Client;

pub struct ApiService {
    client: Client,
    base_url: String,
    jellyfin_url: String,
    jellyfin_username: String,
    jellyfin_password: String,
}

impl ApiService {
    pub fn new() -> Self {
        let client = Client::builder()
            .timeout(std::time::Duration::from_secs(10))
            .connect_timeout(std::time::Duration::from_secs(5))
            .pool_idle_timeout(std::time::Duration::from_secs(90))
            .pool_max_idle_per_host(10)
            .build()
            .unwrap_or_else(|_| Client::new());

        Self {
            client,
            base_url: "https://api.rockvilletollandsda.church".to_string(),
            jellyfin_url: std::env::var("JELLYFIN_SERVER_URL")
                .unwrap_or_else(|_| "https://jellyfin.rockvilletollandsda.church".to_string()),
            jellyfin_username: std::env::var("JELLYFIN_USERNAME")
                .unwrap_or_else(|_| "RTSDA Mobile".to_string()),
            jellyfin_password: std::env::var("JELLYFIN_PASSWORD")
                .unwrap_or_else(|_| "KingofMyLife!!".to_string()),
        }
    }

    pub async fn get_config(&self) -> Result<Option<ChurchConfig>> {
        let response = self
            .client
            .get(&format!("{}/api/config", self.base_url))
            .header("User-Agent", "RTSDA-Website/1.0")
            .send()
            .await?;

        if response.status().is_success() {
            let api_response: ApiResponse<ChurchConfig> = response.json().await?;
            Ok(api_response.data)
        } else {
            Ok(None)
        }
    }

    pub async fn get_events(&self, limit: Option<u32>) -> Result<Vec<Event>> {
        let mut url = format!("{}/api/events/upcoming", self.base_url);
        if let Some(limit) = limit {
            url.push_str(&format!("?limit={}", limit));
        }

        let response = self
            .client
            .get(&url)
            .header("User-Agent", "RTSDA-Website/1.0")
            .send()
            .await?;

        if response.status().is_success() {
            let api_response: ApiResponse<Vec<Event>> = response.json().await?;
            Ok(api_response.data.unwrap_or_default())
        } else {
            Ok(vec![])
        }
    }

    pub async fn get_event(&self, id: &str) -> Result<Option<Event>> {
        let response = self
            .client
            .get(&format!("{}/api/events/{}", self.base_url, id))
            .header("User-Agent", "RTSDA-Website/1.0")
            .send()
            .await?;

        if response.status().is_success() {
            let api_response: ApiResponse<Event> = response.json().await?;
            Ok(api_response.data)
        } else {
            Ok(None)
        }
    }

    pub async fn get_bulletins(&self) -> Result<Vec<Bulletin>> {
        let response = self
            .client
            .get(&format!("{}/api/bulletins", self.base_url))
            .header("User-Agent", "RTSDA-Website/1.0")
            .send()
            .await?;

        if response.status().is_success() {
            let api_response: ApiListResponse<Bulletin> = response.json().await?;
            Ok(api_response.data.items)
        } else {
            Ok(vec![])
        }
    }

    pub async fn get_current_bulletin(&self) -> Result<Option<Bulletin>> {
        let response = self
            .client
            .get(&format!("{}/api/bulletins/current", self.base_url))
            .header("User-Agent", "RTSDA-Website/1.0")
            .send()
            .await?;

        if response.status().is_success() {
            let api_response: ApiResponse<Bulletin> = response.json().await?;
            Ok(api_response.data)
        } else {
            Ok(None)
        }
    }

    pub async fn get_bulletin(&self, id: &str) -> Result<Option<Bulletin>> {
        let response = self
            .client
            .get(&format!("{}/api/bulletins/{}", self.base_url, id))
            .header("User-Agent", "RTSDA-Website/1.0")
            .send()
            .await?;

        if response.status().is_success() {
            let api_response: ApiResponse<Bulletin> = response.json().await?;
            Ok(api_response.data)
        } else {
            Ok(None)
        }
    }

    pub async fn get_random_verse(&self) -> Result<Option<BibleVerse>> {
        let response = self
            .client
            .get(&format!("{}/api/bible_verses/random", self.base_url))
            .header("User-Agent", "RTSDA-Website/1.0")
            .send()
            .await?;

        if response.status().is_success() {
            let api_response: ApiResponse<BibleVerse> = response.json().await?;
            Ok(api_response.data)
        } else {
            Ok(None)
        }
    }

    pub async fn submit_contact_form(&self, form: &ContactForm) -> Result<bool> {
        let response = self
            .client
            .post(&format!("{}/api/contact", self.base_url))
            .header("User-Agent", "RTSDA-Website/1.0")
            .json(form)
            .send()
            .await?;

        Ok(response.status().is_success())
    }

    #[allow(dead_code)]
    pub async fn get_sermons(&self, limit: Option<u32>) -> Result<Vec<Sermon>> {
        let mut url = format!("{}/api/sermons", self.base_url);
        if let Some(limit) = limit {
            url.push_str(&format!("?limit={}", limit));
        }

        let response = self
            .client
            .get(&url)
            .header("User-Agent", "RTSDA-Website/1.0")
            .send()
            .await?;

        if response.status().is_success() {
            let api_response: ApiListResponse<Sermon> = response.json().await?;
            Ok(api_response.data.items)
        } else {
            Ok(vec![])
        }
    }

    #[allow(dead_code)]
    pub async fn get_sermon(&self, id: &str) -> Result<Option<Sermon>> {
        let response = self
            .client
            .get(&format!("{}/api/sermons/{}", self.base_url, id))
            .header("User-Agent", "RTSDA-Website/1.0")
            .send()
            .await?;

        if response.status().is_success() {
            let api_response: ApiResponse<Sermon> = response.json().await?;
            Ok(api_response.data)
        } else {
            Ok(None)
        }
    }

    #[allow(dead_code)]
    pub async fn get_recent_sermons(&self, limit: Option<u32>) -> Result<Vec<Sermon>> {
        let mut url = format!("{}/api/sermons/recent", self.base_url);
        if let Some(limit) = limit {
            url.push_str(&format!("?limit={}", limit));
        }

        let response = self
            .client
            .get(&url)
            .header("User-Agent", "RTSDA-Website/1.0")
            .send()
            .await?;

        if response.status().is_success() {
            let api_response: ApiListResponse<Sermon> = response.json().await?;
            Ok(api_response.data.items)
        } else {
            Ok(vec![])
        }
    }

    // Jellyfin integration methods
    pub async fn authenticate_jellyfin(&self) -> Result<Option<(String, String)>> {
        let auth_request = JellyfinAuth {
            username: self.jellyfin_username.clone(),
            pw: self.jellyfin_password.clone(),
            request: serde_json::Value::Object(serde_json::Map::new()),
        };

        let response = self
            .client
            .post(&format!("{}/Users/authenticatebyname", self.jellyfin_url))
            .header("Content-Type", "application/json")
            .header("X-Emby-Authorization", r#"MediaBrowser Client="RTSDA Church Website", Device="Web", DeviceId="church-website", Version="1.0.0""#)
            .json(&auth_request)
            .send()
            .await?;

        if response.status().is_success() {
            let auth_response: JellyfinAuthResponse = response.json().await?;
            Ok(Some((auth_response.access_token, auth_response.user.id)))
        } else {
            Ok(None)
        }
    }

    pub async fn get_jellyfin_libraries(&self) -> Result<Vec<JellyfinLibrary>> {
        let auth = self.authenticate_jellyfin().await?;
        if let Some((token, user_id)) = auth {
            let response = self
                .client
                .get(&format!("{}/Users/{}/Views", self.jellyfin_url, user_id))
                .header("X-Emby-Authorization", format!(r#"MediaBrowser Token="{}""#, token))
                .send()
                .await?;

            if response.status().is_success() {
                let libraries_response: JellyfinLibrariesResponse = response.json().await?;
                let sermon_libraries = libraries_response.items.into_iter()
                    .filter(|lib| lib.name == "Sermons" || lib.name == "LiveStreams")
                    .collect();
                Ok(sermon_libraries)
            } else {
                Ok(vec![])
            }
        } else {
            Ok(vec![])
        }
    }

    pub async fn get_jellyfin_sermons(&self, parent_id: Option<&str>, limit: Option<u32>) -> Result<Vec<JellyfinItem>> {
        let auth = self.authenticate_jellyfin().await?;
        if let Some((token, user_id)) = auth {
            let mut params = vec![
                ("UserId".to_string(), user_id.clone()),
                ("Recursive".to_string(), "true".to_string()),
                ("IncludeItemTypes".to_string(), "Movie,Audio,Video".to_string()),
                ("SortBy".to_string(), "DateCreated".to_string()),
                ("SortOrder".to_string(), "Descending".to_string()),
            ];
            
            if let Some(l) = limit {
                params.push(("Limit".to_string(), l.to_string()));
            }

            if let Some(pid) = parent_id {
                params.push(("ParentId".to_string(), pid.to_string()));
            }

            let url_params: String = params.iter()
                .map(|(k, v)| format!("{}={}", k, v))
                .collect::<Vec<_>>()
                .join("&");

            let response = self
                .client
                .get(&format!("{}/Users/{}/Items?{}", self.jellyfin_url, user_id, url_params))
                .header("X-Emby-Authorization", format!(r#"MediaBrowser Token="{}""#, token))
                .send()
                .await?;

            if response.status().is_success() {
                let items_response: JellyfinItemsResponse = response.json().await?;
                Ok(items_response.items)
            } else {
                Ok(vec![])
            }
        } else {
            Ok(vec![])
        }
    }

    pub async fn get_jellyfin_sermon(&self, sermon_id: &str) -> Result<Option<JellyfinItem>> {
        let auth = self.authenticate_jellyfin().await?;
        if let Some((token, user_id)) = auth {
            let response = self
                .client
                .get(&format!("{}/Users/{}/Items/{}", self.jellyfin_url, user_id, sermon_id))
                .header("X-Emby-Authorization", format!(r#"MediaBrowser Token="{}""#, token))
                .send()
                .await?;

            if response.status().is_success() {
                let sermon: JellyfinItem = response.json().await?;
                Ok(Some(sermon))
            } else {
                Ok(None)
            }
        } else {
            Ok(None)
        }
    }

    pub fn get_jellyfin_stream_url(&self, sermon_id: &str, token: &str) -> String {
        format!("{}/Videos/{}/stream?api_key={}&static=true", self.jellyfin_url, sermon_id, token)
    }
}

pub fn format_event_datetime(start_time: &str, end_time: &str) -> String {
    use chrono::DateTime;
    
    // Parse the datetime strings
    if let (Ok(start), Ok(end)) = (
        DateTime::parse_from_rfc3339(start_time).or_else(|_| DateTime::parse_from_str(start_time, "%Y-%m-%dT%H:%M:%S%.fZ")),
        DateTime::parse_from_rfc3339(end_time).or_else(|_| DateTime::parse_from_str(end_time, "%Y-%m-%dT%H:%M:%S%.fZ"))
    ) {
        let start_date = start.format("%a, %b %d").to_string();
        let start_time_str = start.format("%l:%M %p").to_string().trim().to_string();
        let end_time_str = end.format("%l:%M %p").to_string().trim().to_string();
        
        // Check if it's an all-day event (starts at midnight)
        if start.format("%H:%M:%S").to_string() == "00:00:00" && 
           end.format("%H:%M:%S").to_string() == "00:00:00" {
            return format!("{} - All Day", start_date);
        }
        
        // Check if same day
        if start.date_naive() == end.date_naive() {
            format!("{} at {} - {}", start_date, start_time_str, end_time_str)
        } else {
            let end_date = end.format("%a, %b %d").to_string();
            format!("{} {} - {} {}", start_date, start_time_str, end_date, end_time_str)
        }
    } else {
        // Fallback to simple formatting
        format!("{} - {}", start_time, end_time)
    }
}

pub fn strip_html(html: &str) -> String {
    // Simple HTML stripping and decode basic HTML entities
    let mut result = html.to_string();
    
    // Simple HTML tag removal (basic implementation)
    while let Some(start) = result.find('<') {
        if let Some(end) = result.find('>') {
            if end > start {
                result.replace_range(start..=end, "");
            } else {
                break;
            }
        } else {
            break;
        }
    }
    
    result
        .replace("&nbsp;", " ")
        .replace("&amp;", "&")
        .replace("&lt;", "<")
        .replace("&gt;", ">")
        .replace("&quot;", "\"")
        .trim()
        .to_string()
}

pub fn parse_sermon_title(full_title: &str) -> ParsedSermon {
    // Parse format: "Title - Speaker | Date"
    let parts: Vec<&str> = full_title.split(" | ").collect();
    let title_and_speaker = parts[0];
    let date_from_title = if parts.len() > 1 { Some(parts[1].to_string()) } else { None };
    
    let speaker_parts: Vec<&str> = title_and_speaker.split(" - ").collect();
    let title = speaker_parts[0].trim().to_string();
    let speaker = if speaker_parts.len() > 1 { 
        Some(speaker_parts[1].trim().to_string()) 
    } else { 
        None 
    };
    
    ParsedSermon {
        title,
        speaker,
        date_from_title,
    }
}

pub fn format_duration(ticks: u64) -> String {
    let total_seconds = ticks / 10_000_000;
    let hours = total_seconds / 3600;
    let minutes = (total_seconds % 3600) / 60;
    let seconds = total_seconds % 60;

    if hours > 0 {
        format!("{}:{:02}:{:02}", hours, minutes, seconds)
    } else {
        format!("{}:{:02}", minutes, seconds)
    }
}

pub fn format_date(date_string: &str) -> String {
    use chrono::NaiveDate;
    
    // For datetime strings, extract just the date part to avoid timezone conversion
    let date_only = date_string.split('T').next().unwrap_or(date_string);
    if let Ok(date) = NaiveDate::parse_from_str(date_only, "%Y-%m-%d") {
        date.format("%B %d, %Y").to_string()
    } else {
        date_string.to_string()
    }
}