// Tauri commands wrapping lumotia_storage profile + profile_term CRUD.
// Pattern mirrors tasks.rs — flat imports from `lumotia_storage` with a `db_`
// alias prefix to avoid name collisions with the command functions, plain
// snake_case parameters (Tauri 2.x auto-converts camelCase JS keys),
// `.map_err(|e| e.to_string())` for error conversion, and camelCase DTOs
// for the frontend-facing shape (the storage row types don't derive
// Serialize — same reason TaskRow → TaskDto exists).
//
// The Default profile is guarded at the storage layer (SQLite triggers +
// Rust pre-checks), so no extra guarding is needed here.

use serde::Serialize;

use lumotia_ai_formatting::extract_corrections;
use lumotia_storage::{
    add_profile_term as db_add_profile_term, create_profile as db_create_profile,
    delete_profile as db_delete_profile, delete_profile_term as db_delete_profile_term,
    list_profile_terms as db_list_profile_terms, list_profiles as db_list_profiles,
    update_profile as db_update_profile, ProfileRow, ProfileTermRow,
};

use crate::AppState;

const AUTO_LEARNED_NOTE: &str = "Auto-learned from transcript edit";

/// Frontend-facing profile shape. Matches the object the Svelte profile
/// picker + editor will consume.
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ProfileDto {
    pub id: String,
    pub name: String,
    pub initial_prompt: String,
    pub created_at: String,
}

impl From<ProfileRow> for ProfileDto {
    fn from(r: ProfileRow) -> Self {
        Self {
            id: r.id,
            name: r.name,
            initial_prompt: r.initial_prompt,
            created_at: r.created_at,
        }
    }
}

/// Frontend-facing profile term (dictionary-style vocabulary hint).
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ProfileTermDto {
    pub id: String,
    pub profile_id: String,
    pub term: String,
    pub note: String,
    pub created_at: String,
}

impl From<ProfileTermRow> for ProfileTermDto {
    fn from(r: ProfileTermRow) -> Self {
        Self {
            id: r.id,
            profile_id: r.profile_id,
            term: r.term,
            note: r.note,
            created_at: r.created_at,
        }
    }
}

#[tauri::command]
pub async fn list_profiles_cmd(
    state: tauri::State<'_, AppState>,
) -> Result<Vec<ProfileDto>, String> {
    db_list_profiles(&state.db)
        .await
        .map(|rows| rows.into_iter().map(ProfileDto::from).collect())
        .map_err(|e| e.to_string())
}

#[tauri::command]
pub async fn create_profile_cmd(
    state: tauri::State<'_, AppState>,
    name: String,
    initial_prompt: String,
) -> Result<ProfileDto, String> {
    db_create_profile(&state.db, &name, &initial_prompt)
        .await
        .map(ProfileDto::from)
        .map_err(|e| e.to_string())
}

#[tauri::command]
pub async fn update_profile_cmd(
    state: tauri::State<'_, AppState>,
    id: String,
    name: String,
    initial_prompt: String,
) -> Result<(), String> {
    db_update_profile(&state.db, &id, &name, &initial_prompt)
        .await
        .map_err(|e| e.to_string())
}

#[tauri::command]
pub async fn delete_profile_cmd(
    state: tauri::State<'_, AppState>,
    id: String,
) -> Result<(), String> {
    db_delete_profile(&state.db, &id)
        .await
        .map_err(|e| e.to_string())
}

#[tauri::command]
pub async fn list_profile_terms_cmd(
    state: tauri::State<'_, AppState>,
    profile_id: String,
) -> Result<Vec<ProfileTermDto>, String> {
    db_list_profile_terms(&state.db, &profile_id)
        .await
        .map(|rows| rows.into_iter().map(ProfileTermDto::from).collect())
        .map_err(|e| e.to_string())
}

#[tauri::command]
pub async fn add_profile_term_cmd(
    state: tauri::State<'_, AppState>,
    profile_id: String,
    term: String,
    note: String,
) -> Result<ProfileTermDto, String> {
    db_add_profile_term(&state.db, &profile_id, &term, &note)
        .await
        .map(ProfileTermDto::from)
        .map_err(|e| e.to_string())
}

#[tauri::command]
pub async fn learn_profile_terms_from_edit_cmd(
    state: tauri::State<'_, AppState>,
    profile_id: String,
    original_text: String,
    edited_text: String,
) -> Result<Vec<ProfileTermDto>, String> {
    let existing_terms: Vec<String> = db_list_profile_terms(&state.db, &profile_id)
        .await
        .map_err(|e| e.to_string())?
        .into_iter()
        .map(|row| row.term)
        .collect();

    let corrections = extract_corrections(&original_text, &edited_text, &existing_terms);
    let mut learned = Vec::new();
    for term in corrections {
        let row = db_add_profile_term(&state.db, &profile_id, &term, AUTO_LEARNED_NOTE)
            .await
            .map_err(|e| e.to_string())?;
        learned.push(ProfileTermDto::from(row));
    }

    Ok(learned)
}

#[tauri::command]
pub async fn delete_profile_term_cmd(
    state: tauri::State<'_, AppState>,
    id: String,
) -> Result<(), String> {
    db_delete_profile_term(&state.db, &id)
        .await
        .map_err(|e| e.to_string())
}
