// Tauri commands for human-in-the-loop feedback capture and retrieval.
// Phase 2 of the feature-complete roadmap: thumbs + correction capture
// on AI-generated output feeds a few-shot loop that conditions future
// prompts on the user's preferred style.

use serde::{Deserialize, Serialize};

use kon_storage::{
    list_feedback_examples as db_list_feedback_examples, record_feedback as db_record_feedback,
    FeedbackRow, FeedbackTargetType, RecordFeedbackParams,
};

use crate::AppState;

#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RecordFeedbackInput {
    /// One of "microstep", "task_extraction", "cleanup".
    pub target_type: String,
    /// Optional surface-specific id (subtask id, task id, transcript id).
    #[serde(default)]
    pub target_id: Option<String>,
    /// -1 = thumbs down, 0 = correction (neutral), +1 = thumbs up.
    pub rating: i8,
    #[serde(default)]
    pub original_text: Option<String>,
    #[serde(default)]
    pub corrected_text: Option<String>,
    /// Freeform JSON context: e.g. the parent task text, the transcript
    /// chunk the AI was given, etc. Used later by the prompt builder
    /// to reconstruct the (input, preferred-output) pair.
    #[serde(default)]
    pub context_json: Option<String>,
    #[serde(default)]
    pub profile_id: Option<String>,
}

#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct FeedbackDto {
    pub id: i64,
    pub target_type: String,
    pub target_id: Option<String>,
    pub rating: i64,
    pub original_text: Option<String>,
    pub corrected_text: Option<String>,
    pub context_json: Option<String>,
    pub profile_id: String,
    pub created_at: String,
}

impl From<FeedbackRow> for FeedbackDto {
    fn from(r: FeedbackRow) -> Self {
        Self {
            id: r.id,
            target_type: r.target_type,
            target_id: r.target_id,
            rating: r.rating,
            original_text: r.original_text,
            corrected_text: r.corrected_text,
            context_json: r.context_json,
            profile_id: r.profile_id,
            created_at: r.created_at,
        }
    }
}

fn parse_target_type(raw: &str) -> Result<FeedbackTargetType, String> {
    FeedbackTargetType::parse(raw).ok_or_else(|| format!("unknown feedback target_type: {raw}"))
}

#[tauri::command]
pub async fn record_feedback(
    state: tauri::State<'_, AppState>,
    input: RecordFeedbackInput,
) -> Result<i64, String> {
    let target_type = parse_target_type(&input.target_type)?;
    db_record_feedback(
        &state.db,
        RecordFeedbackParams {
            target_type,
            target_id: input.target_id,
            rating: input.rating,
            original_text: input.original_text,
            corrected_text: input.corrected_text,
            context_json: input.context_json,
            profile_id: input.profile_id,
        },
    )
    .await
    .map_err(|e| e.to_string())
}

#[tauri::command]
pub async fn list_feedback_examples_cmd(
    state: tauri::State<'_, AppState>,
    target_type: String,
    limit: Option<i64>,
    min_rating: Option<i8>,
    profile_id: Option<String>,
) -> Result<Vec<FeedbackDto>, String> {
    let target = parse_target_type(&target_type)?;
    let limit = limit.unwrap_or(8).clamp(1, 64);
    let min_rating = min_rating.unwrap_or(0).clamp(-1, 1);
    let rows =
        db_list_feedback_examples(&state.db, target, limit, min_rating, profile_id.as_deref())
            .await
            .map_err(|e| e.to_string())?;
    Ok(rows.into_iter().map(FeedbackDto::from).collect())
}
