use crate::error::AppError;
use crate::models::agent::{Agent, AgentRole};
use crate::models::credential::TuleapCredentials;
use crate::models::ticket::ProcessedTicket;
use crate::models::tracker::{FilterGroup, NewWatchedTracker, TrackerUpdate, WatchedTracker};
use crate::services::crypto;
use crate::services::tuleap_client::TuleapClient;
use crate::AppState;
use serde::Deserialize;
use tauri::State;

fn build_tuleap_client(
    state: &State<AppState>,
    project_id: &str,
) -> Result<TuleapClient, AppError> {
    let db = state
        .db
        .lock()
        .map_err(|e| AppError::from(format!("Database lock failed: {}", e)))?;

    let cred = TuleapCredentials::get_for_project(&db, project_id)?
        .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)?;

    Ok(TuleapClient::new(
        &state.http_client,
        &cred.tuleap_url,
        &cred.username,
        &password,
    ))
}

fn ensure_agent_role(
    db: &rusqlite::Connection,
    agent_id: &str,
    expected: AgentRole,
) -> Result<(), AppError> {
    let agent = Agent::get_by_id(db, agent_id)?;
    if agent.role != expected {
        return Err(AppError::from(format!(
            "Agent '{}' has role '{}', expected '{}'",
            agent.name,
            agent.role.as_str(),
            expected.as_str()
        )));
    }
    Ok(())
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct AddTrackerPayload {
    pub project_id: String,
    pub tracker_id: i32,
    pub tracker_label: String,
    pub polling_interval: i32,
    pub analyst_agent_id: String,
    pub developer_agent_id: String,
    pub filters: Vec<FilterGroup>,
}

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

    ensure_agent_role(&db, &payload.analyst_agent_id, AgentRole::Analyst)?;
    ensure_agent_role(&db, &payload.developer_agent_id, AgentRole::Developer)?;

    let tracker = WatchedTracker::insert(
        &db,
        NewWatchedTracker {
            project_id: payload.project_id,
            tracker_id: payload.tracker_id,
            tracker_label: payload.tracker_label,
            polling_interval: payload.polling_interval,
            analyst_agent_id: payload.analyst_agent_id,
            developer_agent_id: payload.developer_agent_id,
            filters: payload.filters,
        },
    )?;

    Ok(tracker)
}

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

    let trackers = WatchedTracker::list_by_project(&db, &project_id)?;
    Ok(trackers)
}

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

    ensure_agent_role(&db, &update.analyst_agent_id, AgentRole::Analyst)?;
    ensure_agent_role(&db, &update.developer_agent_id, AgentRole::Developer)?;

    WatchedTracker::update(&db, &id, update)?;
    Ok(())
}

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

    WatchedTracker::delete(&db, &id)?;
    Ok(())
}

#[tauri::command]
pub async fn get_tracker_fields(
    state: State<'_, AppState>,
    project_id: String,
    tracker_id: i32,
) -> Result<Vec<crate::services::tuleap_client::TrackerField>, AppError> {
    let client = build_tuleap_client(&state, &project_id)?;
    let mut fields = client
        .get_tracker_fields(tracker_id)
        .await
        .map_err(AppError::from)?;

    fields.sort_by(|a, b| a.label.to_lowercase().cmp(&b.label.to_lowercase()));
    for field in &mut fields {
        field
            .values
            .sort_by(|a, b| a.label.to_lowercase().cmp(&b.label.to_lowercase()));
    }

    Ok(fields)
}

#[tauri::command]
pub fn list_processed_tickets(
    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)
}
