use crate::error::AppError;
use crate::models::credential::TuleapCredentials;
use crate::models::ticket::ProcessedTicket;
use crate::models::tracker::WatchedTracker;
use crate::services::{crypto, filter_engine, notifier};
use crate::services::tuleap_client::TuleapClient;
use crate::AppState;
use tauri::{Emitter, State};

#[tauri::command]
pub async fn manual_poll(
    state: State<'_, AppState>,
    app_handle: tauri::AppHandle,
    tracker_id: String,
) -> Result<Vec<ProcessedTicket>, AppError> {
    let (tracker, client) = {
        let db = state
            .db
            .lock()
            .map_err(|e| AppError::from(format!("Database lock failed: {}", e)))?;

        let tracker = WatchedTracker::get_by_id(&db, &tracker_id)?;
        if tracker.status != "valid" {
            return Err(AppError::from(
                "Tracker is invalid. Reconfigure analyst/developer agents first.".to_string(),
            ));
        }

        let cred = TuleapCredentials::get(&db)?
            .ok_or_else(|| AppError::from("No Tuleap credentials configured".to_string()))?;

        let password = crypto::decrypt(&state.encryption_key, &cred.password_encrypted)
            .map_err(AppError::from)?;

        let client = TuleapClient::new(
            &state.http_client,
            &cred.tuleap_url,
            &cred.username,
            &password,
        );

        (tracker, client)
    }; // lock dropped here

    let _ = app_handle.emit(
        "polling-started",
        serde_json::json!({
            "project_id": &tracker.project_id,
            "tracker_id": &tracker.id,
            "tracker_label": &tracker.tracker_label,
            "source": "manual",
        }),
    );

    let artifacts = match client.get_artifacts(tracker.tracker_id).await {
        Ok(a) => a,
        Err(e) => {
            let _ = app_handle.emit(
                "polling-error",
                serde_json::json!({
                    "project_id": &tracker.project_id,
                    "tracker_id": &tracker.id,
                    "tracker_label": &tracker.tracker_label,
                    "source": "manual",
                    "error": e,
                }),
            );
            return Err(AppError::from(e));
        }
    };

    let filtered = filter_engine::apply_filters(&artifacts, &tracker.filters);

    let mut newly_inserted: Vec<ProcessedTicket> = Vec::new();

    {
        let db = state
            .db
            .lock()
            .map_err(|e| AppError::from(format!("Database lock failed: {}", e)))?;

        for artifact in &filtered {
            let artifact_id = artifact
                .get("id")
                .and_then(|v| v.as_i64())
                .unwrap_or(0) as i32;

            let artifact_title = artifact
                .get("title")
                .and_then(|v| v.as_str())
                .unwrap_or("")
                .to_string();

            let artifact_data = serde_json::to_string(artifact)
                .unwrap_or_else(|_| "{}".to_string());

            if let Some(ticket) = ProcessedTicket::insert_if_new(
                &db,
                &tracker.id,
                artifact_id,
                &artifact_title,
                &artifact_data,
            )? {
                newly_inserted.push(ticket);
            }
        }

        WatchedTracker::update_last_polled(&db, &tracker.id)?;
    }

    if !newly_inserted.is_empty() {
        let _ = app_handle.emit(
            "new-tickets-detected",
            serde_json::json!({
                "project_id": &tracker.project_id,
                "tracker_id": &tracker.id,
                "tracker_label": &tracker.tracker_label,
                "count": newly_inserted.len(),
            }),
        );

        for ticket in &newly_inserted {
            notifier::notify_new_ticket(
                &state.db,
                &app_handle,
                &tracker.project_id,
                &ticket.id,
                ticket.artifact_id,
                &ticket.artifact_title,
            );
        }
    }

    let _ = app_handle.emit(
        "polling-finished",
        serde_json::json!({
            "project_id": &tracker.project_id,
            "tracker_id": &tracker.id,
            "tracker_label": &tracker.tracker_label,
            "source": "manual",
            "new_tickets_count": newly_inserted.len(),
        }),
    );

    Ok(newly_inserted)
}

#[tauri::command]
pub fn get_queue_status(
    state: State<'_, AppState>,
    project_id: String,
) -> Result<Vec<ProcessedTicket>, AppError> {
    let db = state
        .db
        .lock()
        .map_err(|e| AppError::from(format!("Database lock failed: {}", e)))?;

    let tickets = ProcessedTicket::list_by_project(&db, &project_id)?;
    Ok(tickets)
}
