use anyhow::Result;
use rusqlite::{params, Row};
use std::sync::Arc;
use crate::data::models::video_generation::{
    VideoGenerationTask, VideoGenerationStatus, VideoGenerationQueryParams,
    VideoPromptConfig, VideoGenerationResult
};
use crate::infrastructure::database::Database;

/// 视频生成任务仓库
/// 遵循 Tauri 开发规范的仓库设计模式
#[derive(Clone)]
pub struct VideoGenerationRepository {
    database: Arc<Database>,
}

impl VideoGenerationRepository {
    /// 创建新的视频生成任务仓库实例
    pub fn new(database: Arc<Database>) -> Self {
        Self { database }
    }

    /// 初始化数据库表
    pub fn init_tables(&self) -> Result<()> {
        let conn = self.database.get_connection();
        let conn = conn.lock().unwrap();

        conn.execute(
            "CREATE TABLE IF NOT EXISTS video_generation_tasks (
                id TEXT PRIMARY KEY,
                model_id TEXT NOT NULL,
                product TEXT NOT NULL,
                scene TEXT NOT NULL,
                model_desc TEXT NOT NULL,
                template TEXT NOT NULL,
                duplicate INTEGER NOT NULL DEFAULT 1,
                selected_photos TEXT NOT NULL, -- JSON array of photo IDs
                status TEXT NOT NULL,
                video_urls TEXT, -- JSON array of video URLs
                video_paths TEXT, -- JSON array of local video paths
                generation_time INTEGER, -- milliseconds
                api_response TEXT,
                error_message TEXT,
                created_at DATETIME NOT NULL,
                updated_at DATETIME NOT NULL,
                completed_at DATETIME,
                FOREIGN KEY (model_id) REFERENCES models (id)
            )",
            [],
        )?;

        Ok(())
    }

    /// 创建视频生成任务
    pub fn create(&self, task: &VideoGenerationTask) -> Result<()> {
        let conn = self.database.get_connection();
        let conn = conn.lock().unwrap();

        let selected_photos_json = serde_json::to_string(&task.selected_photos)?;
        let video_urls_json = task.result.as_ref()
            .map(|r| serde_json::to_string(&r.video_urls))
            .transpose()?;
        let video_paths_json = task.result.as_ref()
            .map(|r| serde_json::to_string(&r.video_paths))
            .transpose()?;

        conn.execute(
            "INSERT INTO video_generation_tasks (
                id, model_id, product, scene, model_desc, template, duplicate,
                selected_photos, status, video_urls, video_paths, generation_time,
                api_response, error_message, created_at, updated_at, completed_at
            ) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15, ?16, ?17)",
            params![
                task.id,
                task.model_id,
                task.prompt_config.product,
                task.prompt_config.scene,
                task.prompt_config.model_desc,
                task.prompt_config.template,
                task.prompt_config.duplicate,
                selected_photos_json,
                format!("{:?}", task.status),
                video_urls_json,
                video_paths_json,
                task.result.as_ref().map(|r| r.generation_time as i64),
                task.result.as_ref().and_then(|r| r.api_response.as_ref()),
                task.error_message,
                task.created_at.format("%Y-%m-%d %H:%M:%S").to_string(),
                task.updated_at.format("%Y-%m-%d %H:%M:%S").to_string(),
                task.completed_at.map(|dt| dt.format("%Y-%m-%d %H:%M:%S").to_string()),
            ],
        )?;

        Ok(())
    }

    /// 根据ID获取视频生成任务
    pub fn get_by_id(&self, id: &str) -> Result<Option<VideoGenerationTask>> {
        let conn = self.database.get_connection();
        let conn = conn.lock().unwrap();

        let mut stmt = conn.prepare(
            "SELECT id, model_id, product, scene, model_desc, template, duplicate,
                    selected_photos, status, video_urls, video_paths, generation_time,
                    api_response, error_message, created_at, updated_at, completed_at
             FROM video_generation_tasks WHERE id = ?1"
        )?;

        let task_iter = stmt.query_map([id], |row| {
            self.row_to_task(row)
        })?;

        for task in task_iter {
            return Ok(Some(task?));
        }

        Ok(None)
    }

    /// 根据查询参数获取视频生成任务列表
    pub fn search(&self, params: &VideoGenerationQueryParams) -> Result<Vec<VideoGenerationTask>> {
        let conn = self.database.get_connection();
        let conn = conn.lock().unwrap();

        let mut query = String::from(
            "SELECT id, model_id, product, scene, model_desc, template, duplicate,
                    selected_photos, status, video_urls, video_paths, generation_time,
                    api_response, error_message, created_at, updated_at, completed_at
             FROM video_generation_tasks WHERE 1=1"
        );

        let mut query_params: Vec<Box<dyn rusqlite::ToSql>> = Vec::new();

        if let Some(ref model_id) = params.model_id {
            query.push_str(" AND model_id = ?");
            query_params.push(Box::new(model_id.clone()));
        }

        if let Some(ref status) = params.status {
            query.push_str(" AND status = ?");
            query_params.push(Box::new(format!("{:?}", status)));
        }

        query.push_str(" ORDER BY created_at DESC");

        if let Some(limit) = params.limit {
            query.push_str(" LIMIT ?");
            query_params.push(Box::new(limit as i64));
        }

        if let Some(offset) = params.offset {
            query.push_str(" OFFSET ?");
            query_params.push(Box::new(offset as i64));
        }

        let mut stmt = conn.prepare(&query)?;
        let param_refs: Vec<&dyn rusqlite::ToSql> = query_params.iter().map(|p| p.as_ref()).collect();

        let task_iter = stmt.query_map(param_refs.as_slice(), |row| {
            self.row_to_task(row)
        })?;

        let mut tasks = Vec::new();
        for task in task_iter {
            tasks.push(task?);
        }

        Ok(tasks)
    }

    /// 更新视频生成任务
    pub fn update(&self, task: &VideoGenerationTask) -> Result<()> {
        let conn = self.database.get_connection();
        let conn = conn.lock().unwrap();

        let selected_photos_json = serde_json::to_string(&task.selected_photos)?;
        let video_urls_json = task.result.as_ref()
            .map(|r| serde_json::to_string(&r.video_urls))
            .transpose()?;
        let video_paths_json = task.result.as_ref()
            .map(|r| serde_json::to_string(&r.video_paths))
            .transpose()?;

        conn.execute(
            "UPDATE video_generation_tasks SET
                model_id = ?2, product = ?3, scene = ?4, model_desc = ?5, template = ?6,
                duplicate = ?7, selected_photos = ?8, status = ?9, video_urls = ?10,
                video_paths = ?11, generation_time = ?12, api_response = ?13,
                error_message = ?14, updated_at = ?15, completed_at = ?16
             WHERE id = ?1",
            params![
                task.id,
                task.model_id,
                task.prompt_config.product,
                task.prompt_config.scene,
                task.prompt_config.model_desc,
                task.prompt_config.template,
                task.prompt_config.duplicate,
                selected_photos_json,
                format!("{:?}", task.status),
                video_urls_json,
                video_paths_json,
                task.result.as_ref().map(|r| r.generation_time as i64),
                task.result.as_ref().and_then(|r| r.api_response.as_ref()),
                task.error_message,
                task.updated_at.format("%Y-%m-%d %H:%M:%S").to_string(),
                task.completed_at.map(|dt| dt.format("%Y-%m-%d %H:%M:%S").to_string()),
            ],
        )?;

        Ok(())
    }

    /// 删除视频生成任务
    pub fn delete(&self, id: &str) -> Result<()> {
        let conn = self.database.get_connection();
        let conn = conn.lock().unwrap();

        conn.execute("DELETE FROM video_generation_tasks WHERE id = ?1", [id])?;

        Ok(())
    }

    /// 将数据库行转换为VideoGenerationTask对象
    fn row_to_task(&self, row: &Row) -> rusqlite::Result<VideoGenerationTask> {
        let selected_photos_json: String = row.get("selected_photos")?;
        let selected_photos: Vec<String> = serde_json::from_str(&selected_photos_json)
            .map_err(|_e| rusqlite::Error::InvalidColumnType(
                row.as_ref().column_index("selected_photos").unwrap(),
                "selected_photos".to_string(),
                rusqlite::types::Type::Text
            ))?;

        let status_str: String = row.get("status")?;
        let status = match status_str.as_str() {
            "Pending" => VideoGenerationStatus::Pending,
            "Processing" => VideoGenerationStatus::Processing,
            "Completed" => VideoGenerationStatus::Completed,
            "Failed" => VideoGenerationStatus::Failed,
            "Cancelled" => VideoGenerationStatus::Cancelled,
            _ => VideoGenerationStatus::Pending,
        };

        let result = if let (Some(video_urls_json), Some(video_paths_json)) = 
            (row.get::<_, Option<String>>("video_urls")?, row.get::<_, Option<String>>("video_paths")?) {
            
            let video_urls: Vec<String> = serde_json::from_str(&video_urls_json).unwrap_or_default();
            let video_paths: Vec<String> = serde_json::from_str(&video_paths_json).unwrap_or_default();
            let generation_time: Option<i64> = row.get("generation_time")?;
            let api_response: Option<String> = row.get("api_response")?;

            Some(VideoGenerationResult {
                video_urls,
                video_paths,
                generation_time: generation_time.unwrap_or(0) as u64,
                api_response,
            })
        } else {
            None
        };

        let created_at_str: String = row.get("created_at")?;
        let updated_at_str: String = row.get("updated_at")?;
        let completed_at_str: Option<String> = row.get("completed_at")?;

        Ok(VideoGenerationTask {
            id: row.get("id")?,
            model_id: row.get("model_id")?,
            prompt_config: VideoPromptConfig {
                product: row.get("product")?,
                scene: row.get("scene")?,
                model_desc: row.get("model_desc")?,
                template: row.get("template")?,
                duplicate: row.get::<_, i64>("duplicate")? as u32,
            },
            selected_photos,
            status,
            result,
            error_message: row.get("error_message")?,
            created_at: chrono::DateTime::parse_from_str(&format!("{} +00:00", created_at_str), "%Y-%m-%d %H:%M:%S %z")
                .unwrap().with_timezone(&chrono::Utc),
            updated_at: chrono::DateTime::parse_from_str(&format!("{} +00:00", updated_at_str), "%Y-%m-%d %H:%M:%S %z")
                .unwrap().with_timezone(&chrono::Utc),
            completed_at: completed_at_str.map(|s| 
                chrono::DateTime::parse_from_str(&format!("{} +00:00", s), "%Y-%m-%d %H:%M:%S %z")
                    .unwrap().with_timezone(&chrono::Utc)
            ),
        })
    }
}
