use async_trait::async_trait;
use loco_rs::{
    Result,
    app::{AppContext, Initializer},
};
use sea_orm::{ActiveModelTrait, EntityTrait, IntoActiveModel, QueryOrder, Set};
use std::path::{Path, PathBuf};

use crate::models::_entities::{comments, posts, site_settings};
const FIXTURES_DIR: &str = "src/fixtures";

pub struct ContentSyncInitializer;

#[async_trait]
impl Initializer for ContentSyncInitializer {
    fn name(&self) -> String {
        "content-sync".to_string()
    }

    async fn before_run(&self, app_context: &AppContext) -> Result<()> {
        sync_content(app_context, Path::new(FIXTURES_DIR)).await
    }
}

async fn sync_content(ctx: &AppContext, base: &Path) -> Result<()> {
    sync_site_settings(ctx, base).await?;
    sync_comment_post_slugs(ctx, base).await?;
    Ok(())
}

fn read_fixture_rows(base: &Path, file_name: &str) -> Vec<serde_json::Value> {
    let path: PathBuf = base.join(file_name);
    let seed_data = match std::fs::read_to_string(path) {
        Ok(data) => data,
        Err(_) => return vec![],
    };

    serde_yaml::from_str(&seed_data).unwrap_or_default()
}

fn as_optional_string(value: &serde_json::Value) -> Option<String> {
    value.as_str().and_then(|item| {
        let trimmed = item.trim();
        if trimmed.is_empty() {
            None
        } else {
            Some(trimmed.to_string())
        }
    })
}

fn is_blank(value: &Option<String>) -> bool {
    value.as_deref().map(str::trim).unwrap_or("").is_empty()
}

fn matches_legacy_ai_defaults(settings: &site_settings::Model) -> bool {
    let provider = settings.ai_provider.as_deref().map(str::trim);
    let api_base = settings.ai_api_base.as_deref().map(str::trim);
    let chat_model = settings.ai_chat_model.as_deref().map(str::trim);

    (provider == Some("openai-compatible")
        && api_base == Some("https://api.openai.com/v1")
        && chat_model == Some("gpt-4.1-mini")
        && is_blank(&settings.ai_api_key))
        || (provider == Some("newapi")
            && matches!(
                api_base,
                Some("https://cliproxy.ai.init.cool") | Some("https://cliproxy.ai.init.cool/v1")
            )
            && chat_model == Some("gpt-5.4"))
}

async fn sync_site_settings(ctx: &AppContext, base: &Path) -> Result<()> {
    let rows = read_fixture_rows(base, "site_settings.yaml");
    let Some(seed) = rows.first() else {
        return Ok(());
    };

    let tech_stack = seed["tech_stack"]
        .as_array()
        .map(|items| {
            items
                .iter()
                .filter_map(|item| item.as_str())
                .map(ToString::to_string)
                .collect::<Vec<_>>()
        })
        .filter(|items| !items.is_empty())
        .map(|items| serde_json::json!(items));
    let music_playlist = seed["music_playlist"]
        .as_array()
        .map(|items| {
            items
                .iter()
                .filter_map(|item| {
                    let title = item["title"].as_str()?.trim();
                    let url = item["url"].as_str()?.trim();
                    if title.is_empty() || url.is_empty() {
                        None
                    } else {
                        Some(serde_json::json!({
                            "title": title,
                            "url": url,
                        }))
                    }
                })
                .collect::<Vec<_>>()
        })
        .filter(|items| !items.is_empty())
        .map(serde_json::Value::Array);
    let music_enabled = seed["music_enabled"].as_bool().or(Some(true));
    let maintenance_mode_enabled = seed["maintenance_mode_enabled"].as_bool().or(Some(false));
    let maintenance_access_code = as_optional_string(&seed["maintenance_access_code"]);
    let seo_favicon_url = as_optional_string(&seed["seo_favicon_url"]);
    let comment_verification_mode = as_optional_string(&seed["comment_verification_mode"]);
    let subscription_verification_mode =
        as_optional_string(&seed["subscription_verification_mode"]);
    let comment_turnstile_enabled =
        seed["comment_turnstile_enabled"]
            .as_bool()
            .or(comment_verification_mode
                .as_deref()
                .map(|value| value.eq_ignore_ascii_case("turnstile")));
    let subscription_turnstile_enabled =
        seed["subscription_turnstile_enabled"]
            .as_bool()
            .or(subscription_verification_mode
                .as_deref()
                .map(|value| value.eq_ignore_ascii_case("turnstile")));

    let existing = site_settings::Entity::find()
        .order_by_asc(site_settings::Column::Id)
        .one(&ctx.db)
        .await?;

    if let Some(existing) = existing {
        let mut model = existing.clone().into_active_model();
        let should_upgrade_legacy_ai_defaults = matches_legacy_ai_defaults(&existing);

        if is_blank(&existing.site_name) {
            model.site_name = Set(as_optional_string(&seed["site_name"]));
        }
        if is_blank(&existing.site_short_name) {
            model.site_short_name = Set(as_optional_string(&seed["site_short_name"]));
        }
        if is_blank(&existing.site_url) {
            model.site_url = Set(as_optional_string(&seed["site_url"]));
        }
        if is_blank(&existing.site_title) {
            model.site_title = Set(as_optional_string(&seed["site_title"]));
        }
        if is_blank(&existing.site_description) {
            model.site_description = Set(as_optional_string(&seed["site_description"]));
        }
        if is_blank(&existing.hero_title) {
            model.hero_title = Set(as_optional_string(&seed["hero_title"]));
        }
        if is_blank(&existing.hero_subtitle) {
            model.hero_subtitle = Set(as_optional_string(&seed["hero_subtitle"]));
        }
        if is_blank(&existing.owner_name) {
            model.owner_name = Set(as_optional_string(&seed["owner_name"]));
        }
        if is_blank(&existing.owner_title) {
            model.owner_title = Set(as_optional_string(&seed["owner_title"]));
        }
        if is_blank(&existing.owner_bio) {
            model.owner_bio = Set(as_optional_string(&seed["owner_bio"]));
        }
        if is_blank(&existing.owner_avatar_url) {
            model.owner_avatar_url = Set(as_optional_string(&seed["owner_avatar_url"]));
        }
        if is_blank(&existing.social_github) {
            model.social_github = Set(as_optional_string(&seed["social_github"]));
        }
        if is_blank(&existing.social_twitter) {
            model.social_twitter = Set(as_optional_string(&seed["social_twitter"]));
        }
        if is_blank(&existing.social_email) {
            model.social_email = Set(as_optional_string(&seed["social_email"]));
        }
        if is_blank(&existing.location) {
            model.location = Set(as_optional_string(&seed["location"]));
        }
        if existing.tech_stack.is_none() {
            model.tech_stack = Set(tech_stack);
        }
        if existing.music_playlist.is_none() {
            model.music_playlist = Set(music_playlist);
        }
        if existing.music_enabled.is_none() {
            model.music_enabled = Set(music_enabled);
        }
        if existing.maintenance_mode_enabled.is_none() {
            model.maintenance_mode_enabled = Set(maintenance_mode_enabled);
        }
        if is_blank(&existing.maintenance_access_code) {
            model.maintenance_access_code = Set(maintenance_access_code.clone());
        }
        if is_blank(&existing.seo_favicon_url) {
            model.seo_favicon_url = Set(seo_favicon_url.clone());
        }
        if existing.ai_enabled.is_none() {
            model.ai_enabled = Set(seed["ai_enabled"].as_bool());
        }
        if existing.paragraph_comments_enabled.is_none() {
            model.paragraph_comments_enabled =
                Set(seed["paragraph_comments_enabled"].as_bool().or(Some(true)));
        }
        if existing.comment_verification_mode.is_none() {
            model.comment_verification_mode = Set(comment_verification_mode.clone());
        }
        if existing.comment_turnstile_enabled.is_none() {
            model.comment_turnstile_enabled = Set(comment_turnstile_enabled);
        }
        if existing.subscription_verification_mode.is_none() {
            model.subscription_verification_mode = Set(subscription_verification_mode.clone());
        }
        if existing.subscription_turnstile_enabled.is_none() {
            model.subscription_turnstile_enabled = Set(subscription_turnstile_enabled);
        }
        if is_blank(&existing.turnstile_site_key) {
            model.turnstile_site_key = Set(as_optional_string(&seed["turnstile_site_key"]));
        }
        if is_blank(&existing.turnstile_secret_key) {
            model.turnstile_secret_key = Set(as_optional_string(&seed["turnstile_secret_key"]));
        }
        if should_upgrade_legacy_ai_defaults {
            model.ai_provider = Set(as_optional_string(&seed["ai_provider"]));
            model.ai_api_base = Set(as_optional_string(&seed["ai_api_base"]));
            model.ai_api_key = Set(as_optional_string(&seed["ai_api_key"]));
            model.ai_chat_model = Set(as_optional_string(&seed["ai_chat_model"]));
        }
        if is_blank(&existing.ai_provider) {
            model.ai_provider = Set(as_optional_string(&seed["ai_provider"]));
        }
        if is_blank(&existing.ai_api_base) {
            model.ai_api_base = Set(as_optional_string(&seed["ai_api_base"]));
        }
        if is_blank(&existing.ai_api_key) {
            model.ai_api_key = Set(as_optional_string(&seed["ai_api_key"]));
        }
        if is_blank(&existing.ai_chat_model) {
            model.ai_chat_model = Set(as_optional_string(&seed["ai_chat_model"]));
        }
        if is_blank(&existing.ai_embedding_model) {
            model.ai_embedding_model = Set(as_optional_string(&seed["ai_embedding_model"]));
        }
        if is_blank(&existing.ai_system_prompt) {
            model.ai_system_prompt = Set(as_optional_string(&seed["ai_system_prompt"]));
        }
        if existing.ai_top_k.is_none() {
            model.ai_top_k = Set(seed["ai_top_k"].as_i64().map(|value| value as i32));
        }
        if existing.ai_chunk_size.is_none() {
            model.ai_chunk_size = Set(seed["ai_chunk_size"].as_i64().map(|value| value as i32));
        }

        let _ = model.update(&ctx.db).await;
        return Ok(());
    }

    let model = site_settings::ActiveModel {
        id: Set(seed["id"].as_i64().unwrap_or(1) as i32),
        site_name: Set(as_optional_string(&seed["site_name"])),
        site_short_name: Set(as_optional_string(&seed["site_short_name"])),
        site_url: Set(as_optional_string(&seed["site_url"])),
        site_title: Set(as_optional_string(&seed["site_title"])),
        site_description: Set(as_optional_string(&seed["site_description"])),
        hero_title: Set(as_optional_string(&seed["hero_title"])),
        hero_subtitle: Set(as_optional_string(&seed["hero_subtitle"])),
        owner_name: Set(as_optional_string(&seed["owner_name"])),
        owner_title: Set(as_optional_string(&seed["owner_title"])),
        owner_bio: Set(as_optional_string(&seed["owner_bio"])),
        owner_avatar_url: Set(as_optional_string(&seed["owner_avatar_url"])),
        social_github: Set(as_optional_string(&seed["social_github"])),
        social_twitter: Set(as_optional_string(&seed["social_twitter"])),
        social_email: Set(as_optional_string(&seed["social_email"])),
        location: Set(as_optional_string(&seed["location"])),
        tech_stack: Set(tech_stack),
        music_playlist: Set(music_playlist),
        music_enabled: Set(music_enabled),
        maintenance_mode_enabled: Set(maintenance_mode_enabled),
        maintenance_access_code: Set(maintenance_access_code),
        seo_favicon_url: Set(seo_favicon_url),
        ai_enabled: Set(seed["ai_enabled"].as_bool()),
        paragraph_comments_enabled: Set(seed["paragraph_comments_enabled"]
            .as_bool()
            .or(Some(true))),
        comment_verification_mode: Set(comment_verification_mode),
        comment_turnstile_enabled: Set(comment_turnstile_enabled),
        subscription_verification_mode: Set(subscription_verification_mode),
        subscription_turnstile_enabled: Set(subscription_turnstile_enabled),
        turnstile_site_key: Set(as_optional_string(&seed["turnstile_site_key"])),
        turnstile_secret_key: Set(as_optional_string(&seed["turnstile_secret_key"])),
        ai_provider: Set(as_optional_string(&seed["ai_provider"])),
        ai_api_base: Set(as_optional_string(&seed["ai_api_base"])),
        ai_api_key: Set(as_optional_string(&seed["ai_api_key"])),
        ai_chat_model: Set(as_optional_string(&seed["ai_chat_model"])),
        ai_embedding_model: Set(as_optional_string(&seed["ai_embedding_model"])),
        ai_system_prompt: Set(as_optional_string(&seed["ai_system_prompt"])),
        ai_top_k: Set(seed["ai_top_k"].as_i64().map(|value| value as i32)),
        ai_chunk_size: Set(seed["ai_chunk_size"].as_i64().map(|value| value as i32)),
        ..Default::default()
    };

    let _ = model.insert(&ctx.db).await;
    Ok(())
}

async fn sync_comment_post_slugs(ctx: &AppContext, base: &Path) -> Result<()> {
    let rows = read_fixture_rows(base, "comments.yaml");

    for seed in rows {
        let id = seed["id"].as_i64().unwrap_or(0) as i32;
        let pid = seed["pid"].as_i64().unwrap_or(0) as i32;
        if id == 0 || pid == 0 {
            continue;
        }

        let Some(existing) = comments::Entity::find_by_id(id).one(&ctx.db).await? else {
            continue;
        };

        if existing.post_slug.is_some() {
            continue;
        }

        let Some(post) = posts::Entity::find_by_id(pid).one(&ctx.db).await? else {
            continue;
        };

        let mut model = existing.into_active_model();
        model.post_slug = Set(Some(post.slug));
        let _ = model.update(&ctx.db).await;
    }

    Ok(())
}
