use axum::{
    extract::{Query, State},
    http::StatusCode,
    response::Json,
    routing::{get, post},
    Router,
};
use serde::{Deserialize, Serialize};

use crate::core::db::{schema, Database, PostgresDb};

#[derive(Debug, Deserialize)]
pub struct RegisterFromPersonRequest {
    pub video_uuid: String,
    pub person_id: String,
    pub identity_name: String,
    pub metadata: Option<serde_json::Value>,
}

#[derive(Debug, Serialize)]
pub struct RegisterFromPersonResponse {
    pub success: bool,
    pub message: String,
    pub identity_id: i32,
    pub identity_name: String,
    pub person_id: String,
}

pub fn identity_routes() -> Router<crate::api::server::AppState> {
    Router::new()
        .route("/api/v1/identities/from-person", post(register_from_person))
        .route("/api/v1/identities", get(list_identities))
}

/// Register a Global Identity from a specific Person in a video.
/// This creates/updates the Identity record, links the Person to the Identity,
/// and updates the Person's name to match the Identity.
async fn register_from_person(
    State(_state): State<crate::api::server::AppState>,
    Json(req): Json<RegisterFromPersonRequest>,
) -> Result<Json<RegisterFromPersonResponse>, (StatusCode, String)> {
    let db = match PostgresDb::init().await {
        Ok(db) => db,
        Err(e) => {
            return Err((
                StatusCode::INTERNAL_SERVER_ERROR,
                format!("DB error: {}", e),
            ))
        }
    };

    let mut tx = match db.pool().begin().await {
        Ok(tx) => tx,
        Err(e) => {
            return Err((
                StatusCode::INTERNAL_SERVER_ERROR,
                format!("Tx error: {}", e),
            ))
        }
    };

    // 1. Check if Person exists
    let person_query =
        "SELECT id, name FROM person_identities WHERE person_id = $1 AND video_uuid = $2";
    let person: Option<(i32, Option<String>)> = match sqlx::query_as(person_query)
        .bind(&req.person_id)
        .bind(&req.video_uuid)
        .fetch_optional(&mut *tx)
        .await
    {
        Ok(p) => p,
        Err(e) => {
            return Err((
                StatusCode::INTERNAL_SERVER_ERROR,
                format!("Query error: {}", e),
            ))
        }
    };

    let (person_db_id, _old_name) = match person {
        Some(p) => p,
        None => {
            return Err((
                StatusCode::NOT_FOUND,
                format!(
                    "Person '{}' not found in video '{}'",
                    req.person_id, req.video_uuid
                ),
            ))
        }
    };

    // 2. Check if Identity exists
    let identity_query = "SELECT id FROM identities WHERE name = $1";
    let identity_id: Option<i32> = match sqlx::query_scalar(identity_query)
        .bind(&req.identity_name)
        .fetch_optional(&mut *tx)
        .await
    {
        Ok(id) => id,
        Err(e) => {
            return Err((
                StatusCode::INTERNAL_SERVER_ERROR,
                format!("Query error: {}", e),
            ))
        }
    };

    let final_identity_id = if let Some(id) = identity_id {
        id
    } else {
        // Create new Identity
        let meta_json = req.metadata.clone().unwrap_or(serde_json::json!({}));

        let new_id: i32 = match sqlx::query_scalar(
            r#"
            INSERT INTO identities (name, embedding, metadata)
            VALUES ($1, NULLIF($2, '')::public.vector, $3)
            RETURNING id
        "#,
        )
        .bind(&req.identity_name)
        .bind("".to_string()) // No embedding for now via this API
        .bind(&meta_json)
        .fetch_one(&mut *tx)
        .await
        {
            Ok(id) => id,
            Err(e) => {
                return Err((
                    StatusCode::INTERNAL_SERVER_ERROR,
                    format!("Insert identity error: {}", e),
                ))
            }
        };
        new_id
    };

    // 3. Create Binding
    // Columns: id, identity_id, identity_type, identity_value, confidence, metadata, created_at
    let binding_query = r#"
        INSERT INTO identity_bindings (identity_id, identity_type, identity_value, confidence, metadata)
        VALUES ($1, $2, $3, $4, $5)
        ON CONFLICT DO NOTHING
    "#;

    match sqlx::query(binding_query)
        .bind(final_identity_id)
        .bind("person_id") // identity_type
        .bind(&req.person_id) // identity_value
        .bind(1.0) // confidence
        .bind(&serde_json::json!({"auto_updated": true}))
        .execute(&mut *tx)
        .await
    {
        Ok(_) => {}
        Err(e) => {
            return Err((
                StatusCode::INTERNAL_SERVER_ERROR,
                format!("Binding error: {}", e),
            ))
        }
    };

    // 4. Update Person Name
    let update_person = "UPDATE person_identities SET name = $1 WHERE id = $2";
    match sqlx::query(update_person)
        .bind(&req.identity_name)
        .bind(person_db_id)
        .execute(&mut *tx)
        .await
    {
        Ok(_) => {}
        Err(e) => {
            return Err((
                StatusCode::INTERNAL_SERVER_ERROR,
                format!("Update person error: {}", e),
            ))
        }
    };

    match tx.commit().await {
        Ok(_) => {}
        Err(e) => {
            return Err((
                StatusCode::INTERNAL_SERVER_ERROR,
                format!("Commit error: {}", e),
            ))
        }
    };

    Ok(Json(RegisterFromPersonResponse {
        success: true,
        message: format!(
            "Successfully registered identity '{}' and linked to person '{}'",
            req.identity_name, req.person_id
        ),
        identity_id: final_identity_id,
        identity_name: req.identity_name,
        person_id: req.person_id,
    }))
}

/// List all global identities
async fn list_identities(
    State(_state): State<crate::api::server::AppState>,
    Query(query): Query<ListIdentitiesQuery>,
) -> Result<Json<IdentityListResponse>, (StatusCode, String)> {
    let db = match PostgresDb::init().await {
        Ok(db) => db,
        Err(e) => {
            return Err((
                StatusCode::INTERNAL_SERVER_ERROR,
                format!("DB error: {}", e),
            ))
        }
    };

    let page = query.page.unwrap_or(1);
    let page_size = query.page_size.unwrap_or(20);
    let offset = ((page - 1) as i64) * (page_size as i64);

    // 獲取總數
    let count_sql = "SELECT COUNT(*) FROM identities";
    let total: i64 = match sqlx::query_scalar(count_sql).fetch_one(db.pool()).await {
        Ok(count) => count,
        Err(e) => {
            return Err((
                StatusCode::INTERNAL_SERVER_ERROR,
                format!("Count error: {}", e),
            ))
        }
    };

    let sql = "SELECT id, name, metadata FROM identities ORDER BY id DESC LIMIT $1 OFFSET $2";

    let rows: Vec<(i32, String, Option<serde_json::Value>)> = match sqlx::query_as(sql)
        .bind(page_size as i64)
        .bind(offset)
        .fetch_all(db.pool())
        .await
    {
        Ok(rows) => rows,
        Err(e) => {
            return Err((
                StatusCode::INTERNAL_SERVER_ERROR,
                format!("Query error: {}", e),
            ))
        }
    };

    let identities: Vec<IdentityResponse> = rows
        .into_iter()
        .map(|r| IdentityResponse {
            id: r.0,
            name: r.1,
            metadata: r.2,
        })
        .collect();

    Ok(Json(IdentityListResponse {
        identities,
        count: total,
        page,
        page_size,
    }))
}

#[derive(Debug, Deserialize)]
pub struct ListIdentitiesQuery {
    pub page: Option<usize>,
    pub page_size: Option<usize>,
}

#[derive(Debug, Serialize)]
pub struct IdentityResponse {
    pub id: i32,
    pub name: String,
    pub metadata: Option<serde_json::Value>,
}

#[derive(Debug, Serialize)]
pub struct IdentityListResponse {
    pub identities: Vec<IdentityResponse>,
    pub count: i64,
    pub page: usize,
    pub page_size: usize,
}
