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

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

pub fn identity_routes() -> Router<crate::api::server::AppState> {
    Router::new()
        .route("/api/v1/people", get(list_people))
        .route("/api/v1/people/search", post(search_people))
        .route("/api/v1/people/candidates", get(list_candidates))
        .route("/api/v1/people/{identity_id}/confirm-candidate", post(confirm_candidate))
        .route("/api/v1/people/{identity_id}/reject-candidate", post(reject_candidate))
        .route("/api/v1/files", get(list_files))
        .route("/api/v1/files/{uuid}", get(get_file_detail))
        .route("/api/v1/resources/register", post(register_resource))
        .route("/api/v1/resources/heartbeat", post(heartbeat_resource))
        .route("/api/v1/resources", get(list_resources))
}

// ... (Keep existing functions) ...

// --- People / Identity Endpoints ---

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

#[derive(Debug, Serialize)]
pub struct PeopleResponse {
    pub success: bool,
    pub total: i64,
    pub page: usize,
    pub page_size: usize,
    pub data: Vec<PeopleItem>,
}

#[derive(Debug, Serialize)]
pub struct PeopleItem {
    pub identity_id: Uuid,
    pub name: String,
    pub metadata: serde_json::Value,
    pub created_at: Option<chrono::DateTime<chrono::Utc>>,
}

async fn list_people(
    State(state): State<crate::api::server::AppState>,
    Query(params): Query<PeopleQuery>,
) -> Result<Json<PeopleResponse>, (StatusCode, String)> {
    let page = params.page.unwrap_or(1);
    let page_size = params.page_size.unwrap_or(20);
    let offset = ((page - 1) as i64) * (page_size as i64);

    let records = state.db.list_people(page_size as i32, offset).await
        .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;

    // TODO: Get total count
    let total = 100; // Placeholder

    let data = records.into_iter().map(|r| PeopleItem {
        identity_id: r.uuid,
        name: r.name,
        metadata: r.metadata,
        created_at: r.created_at,
    }).collect();

    Ok(Json(PeopleResponse {
        success: true,
        total,
        page,
        page_size,
        data,
    }))
}

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

async fn search_people(
    State(state): State<crate::api::server::AppState>,
    Json(req): Json<SearchPeopleRequest>,
) -> Result<Json<PeopleResponse>, (StatusCode, String)> {
    let page = req.page.unwrap_or(1);
    let page_size = req.page_size.unwrap_or(20);
    let offset = ((page - 1) as i64) * (page_size as i64);

    let records = state.db.search_people(&req.query, page_size as i32, offset).await
        .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;

    let data: Vec<PeopleItem> = records.into_iter().map(|r| PeopleItem {
        identity_id: r.uuid,
        name: r.name,
        metadata: r.metadata,
        created_at: r.created_at,
    }).collect();

    Ok(Json(PeopleResponse {
        success: true,
        total: data.len() as i64, // Approximation
        page,
        page_size,
        data,
    }))
}

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

#[derive(Debug, Serialize)]
pub struct CandidatesResponse {
    pub success: bool,
    pub total: i64,
    pub page: usize,
    pub page_size: usize,
    pub data: Vec<CandidateItem>,
}

#[derive(Debug, Serialize)]
pub struct CandidateItem {
    pub pre_chunk_id: i64,
    pub file_uuid: Uuid,
    pub data: serde_json::Value,
}

async fn list_candidates(
    State(state): State<crate::api::server::AppState>,
    Query(params): Query<CandidatesQuery>,
) -> Result<Json<CandidatesResponse>, (StatusCode, String)> {
    let page = params.page.unwrap_or(1);
    let page_size = params.page_size.unwrap_or(20);
    let offset = ((page - 1) as i64) * (page_size as i64);

    let records = state.db.get_people_candidates(page_size as i32, offset).await
        .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;

    let data = records.into_iter().map(|r| CandidateItem {
        pre_chunk_id: r.id,
        file_uuid: r.file_uuid,
        data: r.data,
    }).collect();

    Ok(Json(CandidatesResponse {
        success: true,
        total: 0, // TODO
        page,
        page_size,
        data,
    }))
}

// --- Candidate Workflow Endpoints ---

#[derive(Debug, Deserialize)]
pub struct ConfirmCandidateRequest {
    pub pre_chunk_id: i64,
}

#[derive(Debug, Serialize)]
pub struct ConfirmCandidateResponse {
    pub success: bool,
    pub message: String,
}

async fn confirm_candidate(
    State(state): State<crate::api::server::AppState>,
    Path(identity_id_str): Path<String>,
    Json(req): Json<ConfirmCandidateRequest>,
) -> Result<Json<ConfirmCandidateResponse>, (StatusCode, String)> {
    let identity_id = Uuid::parse_str(&identity_id_str)
        .map_err(|e| (StatusCode::BAD_REQUEST, format!("Invalid UUID: {}", e)))?;

    state.db.confirm_candidate(req.pre_chunk_id, identity_id).await
        .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;

    Ok(Json(ConfirmCandidateResponse {
        success: true,
        message: "Candidate confirmed and linked to identity".to_string(),
    }))
}

async fn reject_candidate(
    State(state): State<crate::api::server::AppState>,
    Path(_identity_id_str): Path<String>, // Unused, but consistent with route
    Json(req): Json<ConfirmCandidateRequest>,
) -> Result<Json<ConfirmCandidateResponse>, (StatusCode, String)> {
    state.db.reject_candidate(req.pre_chunk_id).await
        .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;

    Ok(Json(ConfirmCandidateResponse {
        success: true,
        message: "Candidate rejected".to_string(),
    }))
}

// --- Files Endpoints ---

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

#[derive(Debug, Serialize)]
pub struct FilesResponse {
    pub success: bool,
    pub total: i64,
    pub page: usize,
    pub page_size: usize,
    pub data: Vec<FileItem>,
}

#[derive(Debug, Serialize)]
pub struct FileItem {
    pub file_uuid: String,
    pub file_name: String,
    pub file_path: String,
    pub status: String, // From probe or processing status
}

async fn list_files(
    State(state): State<crate::api::server::AppState>,
    Query(params): Query<FilesQuery>,
) -> Result<Json<FilesResponse>, (StatusCode, String)> {
    let page = params.page.unwrap_or(1);
    let page_size = params.page_size.unwrap_or(20);
    let offset = ((page - 1) as i64) * (page_size as i64);

    let records = state.db.list_files(page_size as i32, offset).await
        .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;

    let data = records.into_iter().map(|r| FileItem {
        file_uuid: r.uuid,
        file_name: r.file_name,
        file_path: r.file_path,
        status: "ready".to_string(),
    }).collect();

    Ok(Json(FilesResponse {
        success: true,
        total: 0, // TODO
        page,
        page_size,
        data,
    }))
}

#[derive(Debug, Serialize)]
pub struct FileDetailResponse {
    pub file_uuid: String,
    pub file_name: String,
    pub file_path: String,
    pub metadata: serde_json::Value,
}

async fn get_file_detail(
    State(state): State<crate::api::server::AppState>,
    Path(uuid): Path<String>,
) -> Result<Json<FileDetailResponse>, (StatusCode, String)> {
    // Need a method to get single file
    // For now, placeholder
    Ok(Json(FileDetailResponse {
        file_uuid: uuid,
        file_name: "Unknown".to_string(),
        file_path: "/path/to/file".to_string(),
        metadata: serde_json::json!({}),
    }))
}

// --- Resource Registry Endpoints (Phase 5) ---

#[derive(Debug, Deserialize)]
pub struct RegisterResourceRequest {
    pub resource_id: String,
    pub resource_type: String,
    pub category: String,
    pub capabilities: Option<serde_json::Value>,
    pub config: Option<serde_json::Value>,
    pub metadata: Option<serde_json::Value>,
}

#[derive(Debug, Serialize)]
pub struct ResourceResponse {
    pub success: bool,
    pub message: String,
    pub data: Option<ResourceItem>,
}

#[derive(Debug, Serialize)]
pub struct ResourceItem {
    pub resource_id: String,
    pub resource_type: String,
    pub category: String,
    pub capabilities: Option<serde_json::Value>,
    pub status: String,
    pub last_heartbeat: Option<chrono::DateTime<chrono::Utc>>,
}

async fn register_resource(
    State(state): State<crate::api::server::AppState>,
    Json(req): Json<RegisterResourceRequest>,
) -> Result<Json<ResourceResponse>, (StatusCode, String)> {
    let resource = ResourceRecord {
        resource_id: req.resource_id.clone(),
        resource_type: req.resource_type.clone(),
        category: req.category.clone(),
        capabilities: req.capabilities,
        config: req.config,
        metadata: req.metadata,
        status: "online".to_string(),
        last_heartbeat: None,
        created_at: None,
    };

    state.db.register_resource(resource).await
        .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;

    Ok(Json(ResourceResponse {
        success: true,
        message: "Resource registered successfully".to_string(),
        data: None, // We could return the full record, but simplified for now
    }))
}

#[derive(Debug, Deserialize)]
pub struct HeartbeatRequest {
    pub resource_id: String,
    pub status: Option<String>,
}

async fn heartbeat_resource(
    State(state): State<crate::api::server::AppState>,
    Json(req): Json<HeartbeatRequest>,
) -> Result<Json<ResourceResponse>, (StatusCode, String)> {
    let status = req.status.unwrap_or("online".to_string());
    state.db.heartbeat_resource(&req.resource_id, &status).await
        .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;

    Ok(Json(ResourceResponse {
        success: true,
        message: "Heartbeat received".to_string(),
        data: None,
    }))
}

async fn list_resources(
    State(state): State<crate::api::server::AppState>,
) -> Result<Json<ResourceResponse>, (StatusCode, String)> {
    let records = state.db.list_resources().await
        .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;

    let data: Vec<ResourceItem> = records.into_iter().map(|r| ResourceItem {
        resource_id: r.resource_id,
        resource_type: r.resource_type,
        category: r.category,
        capabilities: r.capabilities,
        status: r.status,
        last_heartbeat: r.last_heartbeat,
    }).collect();

    Ok(Json(ResourceResponse {
        success: true,
        message: "Resources listed".to_string(),
        data: None,
    }))
}
