use rouille::{input::json_input, Request, Response};
use serde::Deserialize;
use serde_json::json;
use std::sync::Arc;

use super::helpers::{get_conn, json_error, require_auth};
use super::AppState;

pub fn get_status(request: &Request, state: &Arc<AppState>) -> Response {
    let mut conn = match get_conn(state) {
        Ok(c) => c,
        Err(e) => return e,
    };
    if let Err(e) = require_auth(request, &mut conn) {
        return e;
    }

    let running: i64 = conn
        .query_one(
            "SELECT COUNT(*) FROM sync_jobs \
             WHERE status IN ('running'::sync_job_status, 'pending'::sync_job_status)",
            &[],
        )
        .map(|row| row.get(0))
        .unwrap_or(0);

    let completed_today: i64 = conn
        .query_one(
            "SELECT COUNT(*) FROM sync_jobs \
             WHERE status = 'completed'::sync_job_status AND created_at::date = CURRENT_DATE",
            &[],
        )
        .map(|row| row.get(0))
        .unwrap_or(0);

    let failed_today: i64 = conn
        .query_one(
            "SELECT COUNT(*) FROM sync_jobs \
             WHERE status = 'failed'::sync_job_status AND created_at::date = CURRENT_DATE",
            &[],
        )
        .map(|row| row.get(0))
        .unwrap_or(0);

    Response::json(&json!({
        "is_running": running > 0,
        "stats": { "running": running, "completed_today": completed_today, "failed_today": failed_today }
    }))
}

pub fn start(request: &Request, state: &Arc<AppState>) -> Response {
    let mut conn = match get_conn(state) {
        Ok(c) => c,
        Err(e) => return e,
    };
    let user = match require_auth(request, &mut conn) {
        Ok(u) => u,
        Err(e) => return e,
    };

    let form: sap_sync_backend::sync::SyncStartRequest = match json_input(request) {
        Ok(f) => f,
        Err(_) => return json_error(400, "Invalid JSON"),
    };

    let _ = conn.execute(
        "INSERT INTO sync_jobs (job_type, sync_direction, status, created_by, created_at) \
         VALUES ($1, $2, 'pending'::sync_job_status, $3, NOW())",
        &[&form.job_type, &form.sync_direction, &user.id],
    );

    Response::json(&json!({
        "message": "Sync job started",
        "job_type": form.job_type,
        "direction": form.sync_direction,
    }))
}

pub fn stop(request: &Request, state: &Arc<AppState>) -> Response {
    let mut conn = match get_conn(state) {
        Ok(c) => c,
        Err(e) => return e,
    };
    if let Err(e) = require_auth(request, &mut conn) {
        return e;
    }

    let _ = conn.execute(
        "UPDATE sync_jobs SET status = 'cancelled'::sync_job_status, completed_at = NOW() \
         WHERE status IN ('running'::sync_job_status, 'pending'::sync_job_status)",
        &[],
    );
    Response::json(&json!({"message": "Sync jobs stopped"}))
}

pub fn list_jobs(request: &Request, state: &Arc<AppState>) -> Response {
    let mut conn = match get_conn(state) {
        Ok(c) => c,
        Err(e) => return e,
    };
    if let Err(e) = require_auth(request, &mut conn) {
        return e;
    }

    match conn.query(
        "SELECT id, job_type, sync_direction, status::text, records_processed, records_failed, \
         created_at::text, started_at::text, completed_at::text \
         FROM sync_jobs ORDER BY created_at DESC LIMIT 20",
        &[],
    ) {
        Ok(rows) => {
            let jobs: Vec<_> = rows
                .into_iter()
                .map(|row| {
                    json!({
                        "id": row.get::<_, i32>(0),
                        "job_type": row.get::<_, String>(1),
                        "sync_direction": row.get::<_, String>(2),
                        "status": row.get::<_, String>(3),
                        "records_processed": row.get::<_, i32>(4),
                        "records_failed": row.get::<_, i32>(5),
                        "created_at": row.get::<_, String>(6),
                        "started_at": row.get::<_, Option<String>>(7),
                        "completed_at": row.get::<_, Option<String>>(8),
                    })
                })
                .collect();
            Response::json(&json!({"jobs": jobs}))
        }
        Err(_) => json_error(500, "Database error"),
    }
}

pub fn simulate(request: &Request, state: &Arc<AppState>) -> Response {
    let mut conn = match get_conn(state) {
        Ok(c) => c,
        Err(e) => return e,
    };
    if let Err(e) = require_auth(request, &mut conn) {
        return e;
    }

    let form: sap_sync_backend::sync::SyncStartRequest = match json_input(request) {
        Ok(f) => f,
        Err(_) => return json_error(400, "Invalid JSON"),
    };

    match conn.query(
        "SELECT sap_customer_id, plesk_customer_id, plesk_subscription_id FROM customers",
        &[],
    ) {
        Ok(rows) => {
            let len = rows.len();
            let jobs: Vec<_> = rows
                .into_iter()
                .map(|_| {
                    json!({
                        "id": 0,
                        "job_type": form.job_type,
                        "sync_direction": form.sync_direction,
                        "status": "completed",
                        "records_processed": len as i32,
                        "records_failed": 0,
                        "created_at": chrono::Utc::now().to_rfc3339(),
                        "started_at": chrono::Utc::now().to_rfc3339(),
                        "completed_at": chrono::Utc::now().to_rfc3339(),
                    })
                })
                .collect();
            Response::json(&json!({"jobs": jobs}))
        }
        Err(_) => json_error(500, "Database error"),
    }
}

pub fn list_conflicts(request: &Request, state: &Arc<AppState>) -> Response {
    let mut conn = match get_conn(state) {
        Ok(c) => c,
        Err(e) => return e,
    };
    if let Err(e) = require_auth(request, &mut conn) {
        return e;
    }

    match conn.query(
        "SELECT id, sync_job_id, entity_type, entity_id, resolution_status, \
         COALESCE(metadata::text, '{}') as source_data, \
         COALESCE(conflict_details::text, '{}') as conflict_details \
         FROM sync_logs WHERE conflict_details IS NOT NULL \
         ORDER BY timestamp DESC LIMIT 100",
        &[],
    ) {
        Ok(rows) => {
            let conflicts: Vec<_> = rows
                .iter()
                .map(|row| {
                    let source_str: String = row.get("source_data");
                    let conflict_str: String = row.get("conflict_details");
                    json!({
                        "id": row.get::<_, i32>("id"),
                        "sync_job_id": row.get::<_, i32>("sync_job_id"),
                        "entity_type": row.get::<_, String>("entity_type"),
                        "entity_id": row.get::<_, String>("entity_id"),
                        "resolution_status": row.get::<_, String>("resolution_status"),
                        "source_data": serde_json::from_str::<serde_json::Value>(&source_str).unwrap_or(json!({})),
                        "conflict_details": serde_json::from_str::<serde_json::Value>(&conflict_str).unwrap_or(json!({})),
                    })
                })
                .collect();
            Response::json(&conflicts)
        }
        Err(e) => json_error(500, &format!("Query error: {}", e)),
    }
}

pub fn resolve_conflict(request: &Request, state: &Arc<AppState>, id: i32) -> Response {
    #[derive(Deserialize)]
    struct ResolveForm {
        action: String,
        #[allow(dead_code)]
        resolved_data: Option<serde_json::Value>,
    }

    let form: ResolveForm = match json_input(request) {
        Ok(f) => f,
        Err(_) => return json_error(400, "Invalid JSON"),
    };

    let mut conn = match get_conn(state) {
        Ok(c) => c,
        Err(e) => return e,
    };
    if let Err(e) = require_auth(request, &mut conn) {
        return e;
    }

    match conn.execute(
        "UPDATE sync_logs SET resolution_status = 'resolved', resolution_action = $1, \
         resolved_at = CURRENT_TIMESTAMP WHERE id = $2",
        &[&form.action, &id],
    ) {
        Ok(0) => json_error(404, "Conflict not found"),
        Ok(_) => Response::json(&json!({"message": "Conflict resolved"})),
        Err(e) => json_error(500, &format!("Update error: {}", e)),
    }
}
