//! Content models and data structures

use std::collections::HashMap;

use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use uuid::Uuid;

use crate::content::traits::ContentItemTrait;

/// WASM-compatible current timestamp function
fn current_utc_time() -> DateTime<Utc> {
    #[cfg(target_arch = "wasm32")]
    {
        // For WASM, use JavaScript Date API
        use web_sys::js_sys::Date;
        let timestamp_ms = Date::now() as i64;
        DateTime::from_timestamp_millis(timestamp_ms)
            .unwrap_or_else(|| DateTime::from_timestamp(0, 0).unwrap())
    }
    #[cfg(not(target_arch = "wasm32"))]
    {
        // For native, use standard chrono
        Utc::now()
    }
}

use super::metadata::MarkdownMetadata;
use super::types::{ContentFormat, ContentState, ContentType};
use crate::content::traits::ContentCardItem;

/// Category data with emoji
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct CategoryData {
    pub emoji: String,
}

/// Tag data with emoji
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct TagData {
    pub emoji: String,
}

/// Filter index data structure for category and tag filtering with emoji
/// support
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct FilterIndex {
    pub generated_at: String,
    pub content_type: String,
    pub language: String,
    #[serde(default = "default_total_posts")]
    pub total_posts: usize,
    pub categories: HashMap<String, CategoryData>,
    pub tags: HashMap<String, TagData>,
}

/// Default value for published field when not present in JSON
fn default_published() -> bool {
    true // Default to published for existing content
}

/// Default value for total_posts when not present in JSON
fn default_total_posts() -> usize {
    0 // Default to 0 when total_posts is missing
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PageContent {
    pub id: Uuid,
    pub slug: String,
    pub title: String,
    pub name: String,
    pub author: Option<String>,
    pub author_id: Option<Uuid>,
    pub content_type: ContentType,
    pub content_format: ContentFormat,
    pub content: String,
    pub container: String,
    pub state: ContentState,
    pub require_login: bool,
    pub date_init: DateTime<Utc>,
    pub date_end: Option<DateTime<Utc>>,
    pub created_at: DateTime<Utc>,
    pub updated_at: DateTime<Utc>,
    pub published_at: Option<DateTime<Utc>>,
    pub metadata: HashMap<String, String>,
    pub tags: Vec<String>,
    pub category: Option<String>,
    pub featured_image: Option<String>,
    pub excerpt: Option<String>,
    pub seo_title: Option<String>,
    pub seo_description: Option<String>,
    pub allow_comments: bool,
    pub view_count: i64,
    pub sort_order: i32,
}

impl PageContent {
    pub fn new(
        slug: String,
        title: String,
        name: String,
        content_type: ContentType,
        content: String,
        container: String,
        author_id: Option<Uuid>,
    ) -> Self {
        let now = current_utc_time();
        Self {
            id: Uuid::new_v4(),
            slug,
            title,
            name,
            author: None,
            author_id,
            content_type,
            content_format: ContentFormat::Markdown,
            content,
            container,
            state: ContentState::Draft,
            require_login: false,
            date_init: now,
            date_end: None,
            created_at: now,
            updated_at: now,
            published_at: None,
            metadata: HashMap::new(),
            tags: Vec::new(),
            category: None,
            featured_image: None,
            excerpt: None,
            seo_title: None,
            seo_description: None,
            allow_comments: true,
            view_count: 0,
            sort_order: 0,
        }
    }

    pub fn is_published(&self) -> bool {
        matches!(self.state, ContentState::Published)
    }

    pub fn is_accessible(&self, user_authenticated: bool) -> bool {
        if self.require_login && !user_authenticated {
            return false;
        }

        match self.state {
            ContentState::Published => true,
            ContentState::Scheduled => {
                if let Some(publish_date) = self.published_at {
                    current_utc_time() >= publish_date
                } else {
                    false
                }
            }
            _ => false,
        }
    }

    pub fn is_active(&self) -> bool {
        let now = current_utc_time();

        if now < self.date_init {
            return false;
        }

        if let Some(end_date) = self.date_end {
            if now > end_date {
                return false;
            }
        }

        true
    }

    pub fn should_display(&self, user_authenticated: bool) -> bool {
        self.is_accessible(user_authenticated) && self.is_active()
    }

    pub fn set_published(&mut self) {
        self.state = ContentState::Published;
        self.published_at = Some(current_utc_time());
        self.updated_at = current_utc_time();
    }

    pub fn set_scheduled(&mut self, publish_date: DateTime<Utc>) {
        self.state = ContentState::Scheduled;
        self.published_at = Some(publish_date);
        self.updated_at = current_utc_time();
    }

    pub fn add_tag(&mut self, tag: String) {
        if !self.tags.contains(&tag) {
            self.tags.push(tag);
        }
    }

    pub fn remove_tag(&mut self, tag: &str) {
        self.tags.retain(|t| t != tag);
    }

    pub fn set_metadata(&mut self, key: String, value: String) {
        self.metadata.insert(key, value);
    }

    pub fn get_metadata(&self, key: &str) -> Option<&String> {
        self.metadata.get(key)
    }

    pub fn increment_view_count(&mut self) {
        self.view_count += 1;
    }

    // Builder methods
    pub fn with_content_format(mut self, format: ContentFormat) -> Self {
        self.content_format = format;
        self
    }

    pub fn with_state(mut self, state: ContentState) -> Self {
        self.state = state;
        self
    }

    pub fn with_author(mut self, author: String) -> Self {
        self.author = Some(author);
        self
    }

    pub fn with_tags(mut self, tags: Vec<String>) -> Self {
        self.tags = tags;
        self
    }

    pub fn with_category(mut self, category: String) -> Self {
        self.category = Some(category);
        self
    }

    pub fn with_excerpt(mut self, excerpt: String) -> Self {
        self.excerpt = Some(excerpt);
        self
    }

    pub fn with_featured_image(mut self, image: String) -> Self {
        self.featured_image = Some(image);
        self
    }

    pub fn with_require_login(mut self, require_login: bool) -> Self {
        self.require_login = require_login;
        self
    }
}

// Generic content post structure
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ContentPost {
    pub id: String,
    pub metadata: MarkdownMetadata,
    pub content: String,
    pub html: String,
    pub source_file: String,
    pub html_file: String,
    pub translations: Vec<String>,
    pub content_type: String,
}

// ContentIndexItem has been DEPRECATED and removed
// Use UnifiedContentItem from crate::content::item instead

// All ContentIndexItem functionality has been moved to UnifiedContentItem
// located in crate::content::item

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MarkdownPage {
    pub id: String,
    pub metadata: MarkdownMetadata,
    pub content: String,
    pub html: String,
    pub source_file: String,
    pub path: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ContentIndex {
    #[serde(alias = "posts")]
    pub items: Vec<crate::content::UnifiedContentItem>,
    #[serde(default)]
    pub pages: Vec<MarkdownPage>,
    #[serde(default = "default_language")]
    pub language: String,
    #[serde(default = "default_content_type")]
    pub content_type: String,
}

fn default_language() -> String {
    "en".to_string()
}

fn default_content_type() -> String {
    "generic".to_string()
}

impl Default for ContentIndex {
    fn default() -> Self {
        Self {
            items: Vec::new(),
            pages: Vec::new(),
            language: "en".to_string(),
            content_type: "generic".to_string(),
        }
    }
}

impl ContentIndex {
    /// Get all items of a specific content type
    pub fn get_items_by_type(
        &self,
        content_type: &str,
    ) -> Vec<&crate::content::UnifiedContentItem> {
        self.items
            .iter()
            .filter(|item| item.content_type() == content_type)
            .collect()
    }

    /// Get featured items
    pub fn get_featured_items(&self) -> Vec<&crate::content::UnifiedContentItem> {
        self.items.iter().filter(|item| item.featured()).collect()
    }

    /// Get published items
    pub fn get_published_items(&self) -> Vec<&crate::content::UnifiedContentItem> {
        self.items.iter().filter(|item| item.published()).collect()
    }
}
