use crate::{
    invocation::{SkillContext, SkillInput},
    outcome::SkillOutcome,
    skill::{Skill, SkillId},
};
use serde_json::json;

/// Echo: record compression feedback (good/bad) — feeds adaptive threshold tuning.
pub struct EchoSkill;

impl Skill for EchoSkill {
    fn id(&self) -> SkillId {
        SkillId("echo")
    }
    fn display_name(&self) -> &str {
        "Echo"
    }

    fn input_schema(&self) -> serde_json::Value {
        json!({
            "type": "object",
            "properties": {
                "skill_id": { "type": "string", "description": "Which skill's output to rate" },
                "rating": {
                    "type": "string",
                    "enum": ["good", "bad", "partial"],
                    "description": "Was the compression result useful?"
                },
                "lens_used": { "type": "string", "description": "Which lens was applied" },
                "tokens_saved": { "type": "integer" },
                "note": { "type": "string", "description": "Optional free-text feedback" }
            },
            "required": ["skill_id", "rating"]
        })
    }

    fn output_schema(&self) -> serde_json::Value {
        json!({
            "type": "object",
            "properties": {
                "recorded": { "type": "boolean" },
                "feedback_id": { "type": "string" }
            }
        })
    }

    fn execute(&self, input: SkillInput, _ctx: &SkillContext) -> anyhow::Result<SkillOutcome> {
        let skill_id = input.get_str("skill_id").unwrap_or("unknown").to_string();
        let rating = input.get_str("rating").unwrap_or("partial").to_string();
        let lens_used = input.get_str("lens_used").unwrap_or("").to_string();
        let tokens_saved = input.get_u64("tokens_saved").unwrap_or(0) as i64;
        let note = input.get_str("note").unwrap_or("").to_string();

        let feedback_id = record_feedback(&skill_id, &rating, &lens_used, tokens_saved, &note);

        Ok(SkillOutcome::success(
            "echo",
            json!({
                "recorded": feedback_id.is_some(),
                "feedback_id": feedback_id.unwrap_or_default()
            }),
        ))
    }
}

fn record_feedback(
    skill_id: &str,
    rating: &str,
    lens_used: &str,
    tokens_saved: i64,
    note: &str,
) -> Option<String> {
    let db_path = std::path::PathBuf::from(std::env::var("HOME").ok()?)
        .join(".bctx")
        .join("feedback.db");
    let conn = rusqlite::Connection::open(&db_path).ok()?;

    conn.execute_batch(
        "CREATE TABLE IF NOT EXISTS feedback (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            skill_id TEXT,
            rating TEXT,
            lens_used TEXT,
            tokens_saved INTEGER,
            note TEXT,
            recorded_at TEXT DEFAULT (datetime('now'))
        )",
    )
    .ok()?;

    conn.execute(
        "INSERT INTO feedback (skill_id, rating, lens_used, tokens_saved, note) VALUES (?1,?2,?3,?4,?5)",
        rusqlite::params![skill_id, rating, lens_used, tokens_saved, note],
    )
    .ok()?;

    Some(conn.last_insert_rowid().to_string())
}
