use crate::auto_task::intent_compiler::IntentCompiler;
use crate::basic::ScriptService;

use crate::core::shared::models::UserSession;
use crate::core::shared::state::AppState;
#[cfg(feature = "llm")]
use crate::core::config::ConfigManager;
use chrono::{DateTime, Utc};
use diesel::prelude::*;
use diesel::sql_query;
use diesel::sql_types::{Text, Uuid as DieselUuid};
use log::{info, trace, warn};
use serde::{Deserialize, Serialize};
use std::sync::Arc;
use uuid::Uuid;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum IntentType {
    AppCreate,
    Todo,
    Monitor,
    Action,
    Schedule,
    Goal,
    Tool,
    Unknown,
}

impl std::fmt::Display for IntentType {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::AppCreate => write!(f, "APP_CREATE"),
            Self::Todo => write!(f, "TODO"),
            Self::Monitor => write!(f, "MONITOR"),
            Self::Action => write!(f, "ACTION"),
            Self::Schedule => write!(f, "SCHEDULE"),
            Self::Goal => write!(f, "GOAL"),
            Self::Tool => write!(f, "TOOL"),
            Self::Unknown => write!(f, "UNKNOWN"),
        }
    }
}

impl From<&str> for IntentType {
    fn from(s: &str) -> Self {
        match s.to_uppercase().as_str() {
            "APP_CREATE" | "APP" | "APPLICATION" | "CREATE_APP" => Self::AppCreate,
            "TODO" | "TASK" | "REMINDER" => Self::Todo,
            "MONITOR" | "WATCH" | "ALERT" | "ON_CHANGE" => Self::Monitor,
            "ACTION" | "EXECUTE" | "DO" | "RUN" => Self::Action,
            "SCHEDULE" | "SCHEDULED" | "DAILY" | "WEEKLY" | "MONTHLY" | "CRON" => Self::Schedule,
            "GOAL" | "OBJECTIVE" | "TARGET" | "ACHIEVE" => Self::Goal,
            "TOOL" | "COMMAND" | "TRIGGER" | "WHEN_I_SAY" => Self::Tool,
            _ => Self::Unknown,
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ClassifiedIntent {
    pub id: String,
    pub original_text: String,
    pub intent_type: IntentType,
    pub confidence: f64,
    pub entities: ClassifiedEntities,
    pub suggested_name: Option<String>,
    pub requires_clarification: bool,
    pub clarification_question: Option<String>,
    pub alternative_types: Vec<AlternativeClassification>,
    pub classified_at: DateTime<Utc>,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct ClassifiedEntities {
    pub subject: Option<String>,
    pub action: Option<String>,
    pub domain: Option<String>,
    pub time_spec: Option<TimeSpec>,
    pub condition: Option<String>,
    pub recipient: Option<String>,
    pub features: Vec<String>,
    pub tables: Vec<String>,
    pub trigger_phrases: Vec<String>,
    pub target_value: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TimeSpec {
    pub schedule_type: ScheduleType,
    pub time: Option<String>,
    pub day: Option<String>,
    pub interval: Option<String>,
    pub cron_expression: Option<String>,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum ScheduleType {
    Once,
    Daily,
    Weekly,
    Monthly,
    Interval,
    Cron,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AlternativeClassification {
    pub intent_type: IntentType,
    pub confidence: f64,
    pub reason: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IntentResult {
    pub success: bool,
    pub intent_type: IntentType,
    pub message: String,
    pub created_resources: Vec<CreatedResource>,
    pub app_url: Option<String>,
    pub task_id: Option<String>,
    pub schedule_id: Option<String>,
    pub tool_triggers: Vec<String>,
    pub next_steps: Vec<String>,
    pub error: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CreatedResource {
    pub resource_type: String,
    pub name: String,
    pub path: Option<String>,
}

pub struct IntentClassifier {
    state: Arc<AppState>,
    intent_compiler: IntentCompiler,
}

impl IntentClassifier {
    pub fn new(state: Arc<AppState>) -> Self {
        Self {
            state: state.clone(),
            intent_compiler: IntentCompiler::new(state),
        }
    }

    /// Classify an intent and determine which handler should process it
    pub async fn classify(
        &self,
        intent: &str,
        session: &UserSession,
    ) -> Result<ClassifiedIntent, Box<dyn std::error::Error + Send + Sync>> {
        info!(
            "Classifying intent for session {}: {}",
            session.id,
            &intent[..intent.len().min(100)]
        );

        // Use LLM to classify the intent
        let classification = self.classify_with_llm(intent, session.bot_id).await?;

        // Store classification for analytics
        self.store_classification(&classification, session)?;

        Ok(classification)
    }

    /// Classify and then process the intent through the appropriate handler
    pub async fn classify_and_process(
        &self,
        intent: &str,
        session: &UserSession,
    ) -> Result<IntentResult, Box<dyn std::error::Error + Send + Sync>> {
        self.classify_and_process_with_task_id(intent, session, None).await
    }

    /// Classify and then process the intent through the appropriate handler with task tracking
    pub async fn classify_and_process_with_task_id(
        &self,
        intent: &str,
        session: &UserSession,
        task_id: Option<String>,
    ) -> Result<IntentResult, Box<dyn std::error::Error + Send + Sync>> {
        let classification = self.classify(intent, session).await?;

        self.process_classified_intent_with_task_id(&classification, session, task_id)
            .await
    }

    /// Process a classified intent through the appropriate handler
    pub async fn process_classified_intent(
        &self,
        classification: &ClassifiedIntent,
        session: &UserSession,
    ) -> Result<IntentResult, Box<dyn std::error::Error + Send + Sync>> {
        self.process_classified_intent_with_task_id(classification, session, None).await
    }

    /// Process a classified intent through the appropriate handler with task tracking
    pub async fn process_classified_intent_with_task_id(
        &self,
        classification: &ClassifiedIntent,
        session: &UserSession,
        task_id: Option<String>,
    ) -> Result<IntentResult, Box<dyn std::error::Error + Send + Sync>> {
        info!(
            "Processing {} intent: {}",
            classification.intent_type,
            &classification.original_text[..classification.original_text.len().min(50)]
        );

        match classification.intent_type {
            IntentType::AppCreate => self.handle_app_create(classification, session, task_id).await,
            IntentType::Todo => self.handle_todo(classification, session),
            IntentType::Monitor => self.handle_monitor(classification, session),
            IntentType::Action => self.handle_action(classification, session).await,
            IntentType::Schedule => self.handle_schedule(classification, session),
            IntentType::Goal => self.handle_goal(classification, session),
            IntentType::Tool => self.handle_tool(classification, session),
            IntentType::Unknown => Self::handle_unknown(classification),
        }
    }

    /// Use LLM to classify the intent
    async fn classify_with_llm(
        &self,
        intent: &str,
        bot_id: Uuid,
    ) -> Result<ClassifiedIntent, Box<dyn std::error::Error + Send + Sync>> {
        let prompt = format!(
            r#"Classify this user request into one of these intent types:

USER REQUEST: "{intent}"

INTENT TYPES:
- APP_CREATE: Create a full application, utility, calculator, tool, system, etc.
  Keywords: "create", "build", "make", "calculator", "app", "system", "CRM", "tool"
  IMPORTANT: If user wants to CREATE anything (app, calculator, converter, timer, etc), classify as APP_CREATE

- TODO: Simple task or reminder
  Keywords: "call", "remind me", "don't forget", "tomorrow", "later"

- MONITOR: Watch for changes and alert
  Keywords: "alert when", "notify if", "watch", "monitor", "track changes"

- ACTION: Execute something immediately
  Keywords: "send email", "delete", "update all", "export", "do now"

- SCHEDULE: Create recurring automation
  Keywords: "every day", "daily at", "weekly", "monthly", "at 9am"

- GOAL: Long-term objective to achieve
  Keywords: "increase", "improve", "achieve", "reach target", "grow by"

- TOOL: Create a voice/chat command
  Keywords: "when I say", "create command", "shortcut for", "trigger"

YOLO MODE: NEVER ask for clarification. Always make a decision and proceed.
For APP_CREATE: Just build whatever makes sense. A "calculator" = basic calculator app. A "CRM" = customer management app. Be creative and decisive.

Respond with JSON only:
{{
    "intent_type": "APP_CREATE|TODO|MONITOR|ACTION|SCHEDULE|GOAL|TOOL|UNKNOWN",
    "confidence": 0.0-1.0,
    "subject": "main subject or null",
    "action": "main action verb or null",
    "domain": "industry/domain or null",
    "time_spec": {{"type": "ONCE|DAILY|WEEKLY|MONTHLY", "time": "9:00", "day": "monday"}} or null,
    "condition": "trigger condition or null",
    "recipient": "notification recipient or null",
    "features": ["feature1", "feature2"],
    "tables": ["table1", "table2"],
    "trigger_phrases": ["phrase1", "phrase2"],
    "target_value": "metric target or null",
    "suggested_name": "short name for the resource",
    "requires_clarification": false,
    "clarification_question": null,
    "alternatives": []
}}"#
        );

        info!("Starting LLM call for classification, prompt_len={} chars", prompt.len());
        let start = std::time::Instant::now();

        let response = self.call_llm(&prompt, bot_id).await?;
        let elapsed = start.elapsed();
        info!("LLM classification completed in {:?}, response_len={} chars", elapsed, response.len());
        trace!("LLM classification response: {}", &response[..response.len().min(500)]);
        Self::parse_classification_response(&response, intent)
    }

    fn parse_classification_response(
        response: &str,
        original_intent: &str,
    ) -> Result<ClassifiedIntent, Box<dyn std::error::Error + Send + Sync>> {
        #[derive(Deserialize)]
        struct LlmResponse {
            intent_type: String,
            confidence: f64,
            subject: Option<String>,
            action: Option<String>,
            domain: Option<String>,
            time_spec: Option<TimeSpecResponse>,
            condition: Option<String>,
            recipient: Option<String>,
            features: Option<Vec<String>>,
            tables: Option<Vec<String>>,
            trigger_phrases: Option<Vec<String>>,
            target_value: Option<String>,
            suggested_name: Option<String>,
            requires_clarification: Option<bool>,
            clarification_question: Option<String>,
            alternatives: Option<Vec<AlternativeResponse>>,
        }

        #[derive(Deserialize)]
        struct TimeSpecResponse {
            #[serde(rename = "type")]
            schedule_type: Option<String>,
            time: Option<String>,
            day: Option<String>,
            interval: Option<String>,
            cron_expression: Option<String>,
        }

        #[derive(Deserialize)]
        struct AlternativeResponse {
            #[serde(rename = "type")]
            intent_type: String,
            confidence: f64,
            reason: String,
        }

        // Clean response - remove markdown code blocks if present
        let cleaned = response
            .trim()
            .trim_start_matches("```json")
            .trim_start_matches("```JSON")
            .trim_start_matches("```")
            .trim_end_matches("```")
            .trim();

        trace!("Cleaned classification response: {}", &cleaned[..cleaned.len().min(300)]);

        // Try to parse, fall back to heuristic classification
        let parsed: Result<LlmResponse, _> = serde_json::from_str(cleaned);

        match parsed {
            Ok(resp) => {
                let intent_type = IntentType::from(resp.intent_type.as_str());

                let time_spec = resp.time_spec.map(|ts| TimeSpec {
                    schedule_type: match ts.schedule_type.as_deref() {
                        Some("DAILY") => ScheduleType::Daily,
                        Some("WEEKLY") => ScheduleType::Weekly,
                        Some("MONTHLY") => ScheduleType::Monthly,
                        Some("INTERVAL") => ScheduleType::Interval,
                        Some("CRON") => ScheduleType::Cron,
                        _ => ScheduleType::Once,
                    },
                    time: ts.time,
                    day: ts.day,
                    interval: ts.interval,
                    cron_expression: ts.cron_expression,
                });

                let alternatives = resp
                    .alternatives
                    .unwrap_or_default()
                    .into_iter()
                    .map(|a| AlternativeClassification {
                        intent_type: IntentType::from(a.intent_type.as_str()),
                        confidence: a.confidence,
                        reason: a.reason,
                    })
                    .collect();

                Ok(ClassifiedIntent {
                    id: Uuid::new_v4().to_string(),
                    original_text: original_intent.to_string(),
                    intent_type,
                    confidence: resp.confidence,
                    entities: ClassifiedEntities {
                        subject: resp.subject,
                        action: resp.action,
                        domain: resp.domain,
                        time_spec,
                        condition: resp.condition,
                        recipient: resp.recipient,
                        features: resp.features.unwrap_or_default(),
                        tables: resp.tables.unwrap_or_default(),
                        trigger_phrases: resp.trigger_phrases.unwrap_or_default(),
                        target_value: resp.target_value,
                    },
                    suggested_name: resp.suggested_name,
                    requires_clarification: resp.requires_clarification.unwrap_or(false),
                    clarification_question: resp.clarification_question,
                    alternative_types: alternatives,
                    classified_at: Utc::now(),
                })
            }
            Err(e) => {
                warn!("Failed to parse LLM response, using heuristic: {e}");
                trace!("Raw response that failed to parse: {}", &response[..response.len().min(200)]);
                Self::classify_heuristic(original_intent)
            }
        }
    }

    fn classify_heuristic(
        intent: &str,
    ) -> Result<ClassifiedIntent, Box<dyn std::error::Error + Send + Sync>> {
        let lower = intent.to_lowercase();

        let (intent_type, confidence) = if lower.contains("create app")
            || lower.contains("build app")
            || lower.contains("make app")
            || lower.contains("crm")
            || lower.contains("management system")
            || lower.contains("inventory")
            || lower.contains("booking")
            || lower.contains("calculator")
            || lower.contains("website")
            || lower.contains("webpage")
            || lower.contains("web page")
            || lower.contains("landing page")
            || lower.contains("dashboard")
            || lower.contains("form")
            || lower.contains("todo list")
            || lower.contains("todo app")
            || lower.contains("chat")
            || lower.contains("blog")
            || lower.contains("portfolio")
            || lower.contains("store")
            || lower.contains("shop")
            || lower.contains("e-commerce")
            || lower.contains("ecommerce")
            || (lower.contains("create") && lower.contains("html"))
            || (lower.contains("make") && lower.contains("html"))
            || (lower.contains("build") && lower.contains("html"))
            || (lower.contains("create a") && (lower.contains("simple") || lower.contains("basic")))
            || (lower.contains("make a") && (lower.contains("simple") || lower.contains("basic")))
            || (lower.contains("build a") && (lower.contains("simple") || lower.contains("basic")))
            || lower.contains("criar")
            || lower.contains("fazer")
            || lower.contains("construir")
        {
            (IntentType::AppCreate, 0.75)
        } else if lower.contains("remind")
            || lower.contains("call ")
            || lower.contains("tomorrow")
            || lower.contains("don't forget")
        {
            (IntentType::Todo, 0.70)
        } else if lower.contains("alert when")
            || lower.contains("notify if")
            || lower.contains("watch for")
            || lower.contains("monitor")
        {
            (IntentType::Monitor, 0.70)
        } else if lower.contains("send email")
            || lower.contains("delete all")
            || lower.contains("update all")
            || lower.contains("export")
        {
            (IntentType::Action, 0.65)
        } else if lower.contains("every day")
            || lower.contains("daily")
            || lower.contains("weekly")
            || lower.contains("at 9")
            || lower.contains("at 8")
        {
            (IntentType::Schedule, 0.70)
        } else if lower.contains("increase")
            || lower.contains("improve")
            || lower.contains("achieve")
            || lower.contains("grow by")
        {
            (IntentType::Goal, 0.60)
        } else if lower.contains("when i say")
            || lower.contains("create command")
            || lower.contains("shortcut")
        {
            (IntentType::Tool, 0.70)
        } else {
            (IntentType::Unknown, 0.30)
        };

        Ok(ClassifiedIntent {
            id: Uuid::new_v4().to_string(),
            original_text: intent.to_string(),
            intent_type,
            confidence,
            entities: ClassifiedEntities::default(),
            suggested_name: None,
            requires_clarification: intent_type == IntentType::Unknown,
            clarification_question: if intent_type == IntentType::Unknown {
                Some("Could you please clarify what you'd like me to do?".to_string())
            } else {
                None
            },
            alternative_types: Vec::new(),
            classified_at: Utc::now(),
        })
    }

    async fn handle_app_create(
        &self,
        classification: &ClassifiedIntent,
        session: &UserSession,
        task_id: Option<String>,
    ) -> Result<IntentResult, Box<dyn std::error::Error + Send + Sync>> {
        info!("Handling APP_CREATE intent via Orchestrator pipeline");

        let mut orchestrator = if let Some(tid) = task_id {
            crate::auto_task::orchestrator::Orchestrator::with_task_id(
                self.state.clone(),
                tid,
            )
        } else {
            crate::auto_task::orchestrator::Orchestrator::new(self.state.clone())
        };

        let result = orchestrator
            .execute_pipeline(classification, session)
            .await?;

        Ok(IntentResult {
            success: result.success,
            intent_type: IntentType::AppCreate,
            message: result.message,
            created_resources: result
                .created_resources
                .into_iter()
                .map(|r| CreatedResource {
                    resource_type: r.resource_type,
                    name: r.name,
                    path: r.path,
                })
                .collect(),
            app_url: result.app_url,
            task_id: Some(result.task_id),
            schedule_id: None,
            tool_triggers: Vec::new(),
            next_steps: vec![
                "Open the app to start using it".to_string(),
                "Use Designer to customize the app".to_string(),
            ],
            error: result.error,
        })
    }

    fn handle_todo(
        &self,
        classification: &ClassifiedIntent,
        _session: &UserSession,
    ) -> Result<IntentResult, Box<dyn std::error::Error + Send + Sync>> {
        info!("Handling TODO intent");

        let task_id = Uuid::new_v4();
        let title = classification
            .suggested_name
            .clone()
            .unwrap_or_else(|| classification.original_text.clone());

        let mut conn = self.state.conn.get()?;

        // Insert into tasks table (no bot_id column in tasks table)
        sql_query(
            "INSERT INTO tasks (id, title, description, status, priority, created_at)
             VALUES ($1, $2, $3, 'pending', 'normal', NOW())",
        )
        .bind::<DieselUuid, _>(task_id)
        .bind::<Text, _>(&title)
        .bind::<Text, _>(&classification.original_text)
        .execute(&mut conn)?;

        Ok(IntentResult {
            success: true,
            intent_type: IntentType::Todo,
            message: format!("Task saved: {title}"),
            created_resources: vec![CreatedResource {
                resource_type: "task".to_string(),
                name: title,
                path: None,
            }],
            app_url: None,
            task_id: Some(task_id.to_string()),
            schedule_id: None,
            tool_triggers: Vec::new(),
            next_steps: vec!["View tasks in your task list".to_string()],
            error: None,
        })
    }

    fn handle_monitor(
        &self,
        classification: &ClassifiedIntent,
        session: &UserSession,
    ) -> Result<IntentResult, Box<dyn std::error::Error + Send + Sync>> {
        info!("Handling MONITOR intent");

        let subject = classification
            .entities
            .subject
            .clone()
            .unwrap_or_else(|| "data".to_string());
        let condition = classification
            .entities
            .condition
            .clone()
            .unwrap_or_else(|| "changes".to_string());

        // Generate ON CHANGE handler BASIC code
        let handler_name = format!("monitor_{}.bas", subject.to_lowercase().replace(' ', "_"));

        let basic_code = format!(
            r#"' Monitor: {subject}
' Condition: {condition}
' Created: {}

ON CHANGE "{subject}"
    current_value = GET "{subject}"
    IF {condition} THEN
        TALK "Alert: {subject} has changed"
        ' Add notification logic here
    END IF
END ON
"#,
            Utc::now().format("%Y-%m-%d %H:%M")
        );

        // Save to {bot_id}.gbdialog/events/
        let event_path = format!("{}.gbdialog/events/{handler_name}", session.bot_id);
        self.save_basic_file(session.bot_id, &event_path, &basic_code)?;

        Ok(IntentResult {
            success: true,
            intent_type: IntentType::Monitor,
            message: format!("Monitor created for: {subject}"),
            created_resources: vec![CreatedResource {
                resource_type: "event".to_string(),
                name: handler_name,
                path: Some(event_path),
            }],
            app_url: None,
            task_id: None,
            schedule_id: None,
            tool_triggers: Vec::new(),
            next_steps: vec![format!("You'll be notified when {subject} {condition}")],
            error: None,
        })
    }

    async fn handle_action(
        &self,
        classification: &ClassifiedIntent,
        session: &UserSession,
    ) -> Result<IntentResult, Box<dyn std::error::Error + Send + Sync>> {
        info!("Handling ACTION intent");

        // Compile the intent into an execution plan
        let compiled = self
            .intent_compiler
            .compile(&classification.original_text, session)
            .await?;

        // For immediate actions, we'd execute the plan
        // For safety, high-risk actions require approval
        if compiled.risk_assessment.requires_human_review {
            return Ok(IntentResult {
                success: false,
                intent_type: IntentType::Action,
                message: format!(
                    "This action requires approval:\n{}",
                    compiled.risk_assessment.review_reason.unwrap_or_default()
                ),
                created_resources: Vec::new(),
                app_url: None,
                task_id: Some(compiled.id),
                schedule_id: None,
                tool_triggers: Vec::new(),
                next_steps: vec!["Approve the action to proceed".to_string()],
                error: None,
            });
        }

        // Execute low-risk actions immediately using the BASIC interpreter
        let basic_program = &compiled.basic_program;

        if basic_program.is_empty() {
            return Ok(IntentResult {
                success: true,
                intent_type: IntentType::Action,
                message: format!(
                    "Plan created: {}\nSteps: {} (no BASIC code to execute)",
                    compiled.plan.name,
                    compiled.plan.steps.len()
                ),
                created_resources: Vec::new(),
                app_url: None,
                task_id: Some(compiled.id),
                schedule_id: None,
                tool_triggers: Vec::new(),
                next_steps: vec!["Plan ready for manual execution".to_string()],
                error: None,
            });
        }

        // Create ScriptService and execute the BASIC program
        let mut script_service = ScriptService::new(self.state.clone(), session.clone());

        // Load bot config parameters if available
        script_service.load_bot_config_params(&self.state, session.bot_id);

        // Inject task context variables
        let mut context_vars = std::collections::HashMap::new();
        context_vars.insert("task_id".to_string(), compiled.id.clone());
        context_vars.insert("task_name".to_string(), compiled.plan.name.clone());
        context_vars.insert("original_intent".to_string(), compiled.original_intent.clone());
        script_service.inject_config_variables(context_vars);

        // Compile and execute the BASIC program
        let ast = match script_service.compile(basic_program) {
            Ok(ast) => ast,
            Err(e) => {
                let error_msg = format!("Failed to compile BASIC program: {}", e);
                warn!("BASIC compilation failed for task {}: {}", compiled.id, error_msg);
                return Ok(IntentResult {
                    success: false,
                    intent_type: IntentType::Action,
                    message: format!(
                        "Failed to compile: {}\nError: {}",
                        compiled.plan.name,
                        error_msg
                    ),
                    created_resources: Vec::new(),
                    app_url: None,
                    task_id: Some(compiled.id),
                    schedule_id: None,
                    tool_triggers: Vec::new(),
                    next_steps: vec!["Fix the BASIC program syntax and try again".to_string()],
                    error: Some(error_msg),
                });
            }
        };

        let execution_result = script_service.run(&ast);

        match execution_result {
            Ok(result) => {
                let output = result.to_string();
                info!("BASIC execution completed for task {}: {}", compiled.id, &output[..output.len().min(200)]);

                Ok(IntentResult {
                    success: true,
                    intent_type: IntentType::Action,
                    message: format!(
                        "Executed: {}\nResult: {}",
                        compiled.plan.name,
                        if output.is_empty() { "Success".to_string() } else { output }
                    ),
                    created_resources: Vec::new(),
                    app_url: None,
                    task_id: Some(compiled.id),
                    schedule_id: None,
                    tool_triggers: Vec::new(),
                    next_steps: vec!["Action completed successfully".to_string()],
                    error: None,
                })
            }
            Err(e) => {
                let error_msg = format!("{}", e);
                warn!("BASIC execution failed for task {}: {}", compiled.id, error_msg);

                Ok(IntentResult {
                    success: false,
                    intent_type: IntentType::Action,
                    message: format!(
                        "Failed to execute: {}\nError: {}",
                        compiled.plan.name,
                        error_msg
                    ),
                    created_resources: Vec::new(),
                    app_url: None,
                    task_id: Some(compiled.id),
                    schedule_id: None,
                    tool_triggers: Vec::new(),
                    next_steps: vec!["Review the error and try again".to_string()],
                    error: Some(error_msg),
                })
            }
        }
    }

    fn handle_schedule(
        &self,
        classification: &ClassifiedIntent,
        session: &UserSession,
    ) -> Result<IntentResult, Box<dyn std::error::Error + Send + Sync>> {
        info!("Handling SCHEDULE intent");

        let schedule_name = classification
            .suggested_name
            .clone()
            .unwrap_or_else(|| "scheduled-task".to_string())
            .to_lowercase()
            .replace(' ', "-");

        let time_spec = classification
            .entities
            .time_spec
            .as_ref()
            .map(|ts| {
                format!(
                    "{} at {}",
                    match ts.schedule_type {
                        ScheduleType::Daily => "Every day",
                        ScheduleType::Weekly => "Every week",
                        ScheduleType::Monthly => "Every month",
                        _ => "Once",
                    },
                    ts.time.as_deref().unwrap_or("9:00 AM")
                )
            })
            .unwrap_or_else(|| "Every day at 9:00 AM".to_string());

        // Generate scheduler BASIC code
        let scheduler_file = format!("{schedule_name}.bas");
        let basic_code = format!(
            r#"' Scheduler: {schedule_name}
' Schedule: {time_spec}
' Created: {}

SET SCHEDULE "{time_spec}"
    ' Task logic from: {}
    TALK "Running scheduled task: {schedule_name}"
    ' Add your automation logic here
END SCHEDULE
"#,
            Utc::now().format("%Y-%m-%d %H:%M"),
            classification.original_text
        );

        // Save to {bot_id}.gbdialog/schedulers/
        let scheduler_path = format!("{}.gbdialog/schedulers/{scheduler_file}", session.bot_id);
        self.save_basic_file(session.bot_id, &scheduler_path, &basic_code)?;

        let schedule_id = Uuid::new_v4();

        Ok(IntentResult {
            success: true,
            intent_type: IntentType::Schedule,
            message: format!("Scheduler created: {scheduler_file}\nSchedule: {time_spec}"),
            created_resources: vec![CreatedResource {
                resource_type: "scheduler".to_string(),
                name: scheduler_file,
                path: Some(scheduler_path),
            }],
            app_url: None,
            task_id: None,
            schedule_id: Some(schedule_id.to_string()),
            tool_triggers: Vec::new(),
            next_steps: vec![format!("The task will run {time_spec}")],
            error: None,
        })
    }

    fn handle_goal(
        &self,
        classification: &ClassifiedIntent,
        session: &UserSession,
    ) -> Result<IntentResult, Box<dyn std::error::Error + Send + Sync>> {
        info!("Handling GOAL intent");

        let goal_name = classification
            .suggested_name
            .clone()
            .unwrap_or_else(|| "goal".to_string());
        let target = classification
            .entities
            .target_value
            .clone()
            .unwrap_or_else(|| "unspecified".to_string());

        // Goals are more complex - they create a monitoring + action loop
        let basic_code = format!(
            r#"' Goal: {goal_name}
' Target: {target}
' Created: {}

' This goal runs as an autonomous loop
SET GOAL "{goal_name}"
    TARGET = "{target}"

    ' Check current metrics
    current = GET_METRIC "{goal_name}"

    ' LLM analyzes progress and suggests actions
    analysis = LLM "Analyze progress toward {target}. Current: " + current

    ' Execute suggested improvements
    IF analysis.has_action THEN
        EXECUTE analysis.action
    END IF

    ' Report progress
    TALK "Goal progress: " + current + " / " + TARGET
END GOAL
"#,
            Utc::now().format("%Y-%m-%d %H:%M")
        );

        // Save to .gbdialog/goals/
        let goal_file = format!("{}.bas", goal_name.to_lowercase().replace(' ', "-"));
        let goal_path = format!("{}.gbdialog/goals/{goal_file}", session.bot_id);
        self.save_basic_file(session.bot_id, &goal_path, &basic_code)?;

        Ok(IntentResult {
            success: true,
            intent_type: IntentType::Goal,
            message: format!("Goal created: {goal_name}\nTarget: {target}"),
            created_resources: vec![CreatedResource {
                resource_type: "goal".to_string(),
                name: goal_name,
                path: Some(goal_path),
            }],
            app_url: None,
            task_id: None,
            schedule_id: None,
            tool_triggers: Vec::new(),
            next_steps: vec![
                "The system will work toward this goal autonomously".to_string(),
                "Check progress in the Goals dashboard".to_string(),
            ],
            error: None,
        })
    }

    fn handle_tool(
        &self,
        classification: &ClassifiedIntent,
        session: &UserSession,
    ) -> Result<IntentResult, Box<dyn std::error::Error + Send + Sync>> {
        info!("Handling TOOL intent");

        let tool_name = classification
            .suggested_name
            .clone()
            .unwrap_or_else(|| "custom-command".to_string())
            .to_lowercase()
            .replace(' ', "-");

        let triggers = if classification.entities.trigger_phrases.is_empty() {
            vec![tool_name.clone()]
        } else {
            classification.entities.trigger_phrases.clone()
        };

        let triggers_str = triggers
            .iter()
            .map(|t| format!("\"{}\"", t))
            .collect::<Vec<_>>()
            .join(", ");

        // Generate tool BASIC code
        let tool_file = format!("{tool_name}.bas");
        let basic_code = format!(
            r#"' Tool: {tool_name}
' Triggers: {triggers_str}
' Created: {}

TRIGGER {triggers_str}
    ' Command logic from: {}
    TALK "Running command: {tool_name}"
    ' Add your command logic here
END TRIGGER
"#,
            Utc::now().format("%Y-%m-%d %H:%M"),
            classification.original_text
        );

        // Save to {bot_id}.gbdialog/tools/
        let tool_path = format!("{}.gbdialog/tools/{tool_file}", session.bot_id);
        self.save_basic_file(session.bot_id, &tool_path, &basic_code)?;

        Ok(IntentResult {
            success: true,
            intent_type: IntentType::Tool,
            message: format!(
                "Command created: {tool_file}\nTriggers: {}",
                triggers.join(", ")
            ),
            created_resources: vec![CreatedResource {
                resource_type: "tool".to_string(),
                name: tool_file,
                path: Some(tool_path),
            }],
            app_url: None,
            task_id: None,
            schedule_id: None,
            tool_triggers: triggers,
            next_steps: vec!["Say any of the trigger phrases to use the command".to_string()],
            error: None,
        })
    }

    fn handle_unknown(
        classification: &ClassifiedIntent,
    ) -> Result<IntentResult, Box<dyn std::error::Error + Send + Sync>> {
        info!("Handling UNKNOWN intent - requesting clarification");

        let suggestions = if classification.alternative_types.is_empty() {
            "- Create an app\n- Add a task\n- Set up monitoring\n- Schedule automation".to_string()
        } else {
            classification
                .alternative_types
                .iter()
                .map(|a| format!("- {}: {}", a.intent_type, a.reason))
                .collect::<Vec<_>>()
                .join("\n")
        };

        Ok(IntentResult {
            success: false,
            intent_type: IntentType::Unknown,
            message: format!(
                "I'm not sure what you'd like me to do. Could you clarify?\n\nPossible interpretations:\n{}",
                suggestions
            ),
            created_resources: Vec::new(),
            app_url: None,
            task_id: None,
            schedule_id: None,
            tool_triggers: Vec::new(),
            next_steps: vec!["Provide more details about what you want".to_string()],
            error: None,
        })
    }

    // =========================================================================
    // HELPER METHODS
    // =========================================================================

    /// Call LLM for classification
    async fn call_llm(
        &self,
        _prompt: &str,
        _bot_id: Uuid,
    ) -> Result<String, Box<dyn std::error::Error + Send + Sync>> {
        trace!("Calling LLM with prompt length: {}", _prompt.len());

        #[cfg(feature = "llm")]
        {
            let prompt = _prompt;
            let bot_id = _bot_id;
            // Get model and key from bot configuration
            let config_manager = ConfigManager::new(self.state.conn.clone());
            let model = config_manager
                .get_config(&bot_id, "llm-model", None)
                .unwrap_or_else(|_| {
                    config_manager
                        .get_config(&Uuid::nil(), "llm-model", None)
                        .unwrap_or_else(|_| "gpt-4".to_string())
                });
            let key = config_manager
                .get_config(&bot_id, "llm-key", None)
                .unwrap_or_else(|_| {
                    config_manager
                        .get_config(&Uuid::nil(), "llm-key", None)
                        .unwrap_or_default()
                });

            let llm_config = serde_json::json!({
                "temperature": 0.3,
                "max_tokens": 1000
            });
            let response = self
                .state
                .llm_provider
                .generate(prompt, &llm_config, &model, &key)
                .await?;
            Ok(response)
        }

        #[cfg(not(feature = "llm"))]
        {
            warn!("LLM feature not enabled, using heuristic classification");
            Ok("{}".to_string())
        }
    }

    /// Save a BASIC file to the bot's directory
    fn save_basic_file(
        &self,
        bot_id: Uuid,
        path: &str,
        content: &str,
    ) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
        let site_path = self
            .state
            .config
            .as_ref()
            .map(|c| c.site_path.clone())
            .unwrap_or_else(|| format!("{}/sites", crate::core::shared::utils::get_stack_path()));

        let full_path = format!("{}/{}.gbai/{}", site_path, bot_id, path);

        // Create directory if needed
        if let Some(dir) = std::path::Path::new(&full_path).parent() {
            if !dir.exists() {
                std::fs::create_dir_all(dir)?;
            }
        }

        std::fs::write(&full_path, content)?;
        info!("Saved BASIC file: {full_path}");

        Ok(())
    }

    /// Store classification for analytics
    fn store_classification(
        &self,
        classification: &ClassifiedIntent,
        session: &UserSession,
    ) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
        let mut conn = self.state.conn.get()?;

        sql_query(
            "INSERT INTO intent_classifications
             (id, bot_id, session_id, original_text, intent_type, confidence, entities, created_at)
             VALUES ($1, $2, $3, $4, $5, $6, $7, NOW())
             ON CONFLICT DO NOTHING",
        )
        .bind::<DieselUuid, _>(Uuid::parse_str(&classification.id)?)
        .bind::<DieselUuid, _>(session.bot_id)
        .bind::<DieselUuid, _>(session.id)
        .bind::<Text, _>(&classification.original_text)
        .bind::<Text, _>(&classification.intent_type.to_string())
        .bind::<diesel::sql_types::Float8, _>(classification.confidence)
        .bind::<Text, _>(serde_json::to_string(&classification.entities)?)
        .execute(&mut conn)
        .ok(); // Ignore errors - analytics shouldn't break the flow

        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_intent_type_from_str() {
        assert_eq!(IntentType::from("APP_CREATE"), IntentType::AppCreate);
        assert_eq!(IntentType::from("app"), IntentType::AppCreate);
        assert_eq!(IntentType::from("TODO"), IntentType::Todo);
        assert_eq!(IntentType::from("reminder"), IntentType::Todo);
        assert_eq!(IntentType::from("MONITOR"), IntentType::Monitor);
        assert_eq!(IntentType::from("SCHEDULE"), IntentType::Schedule);
        assert_eq!(IntentType::from("daily"), IntentType::Schedule);
        assert_eq!(IntentType::from("unknown_value"), IntentType::Unknown);
    }

    #[test]
    fn test_intent_type_display() {
        assert_eq!(IntentType::AppCreate.to_string(), "APP_CREATE");
        assert_eq!(IntentType::Todo.to_string(), "TODO");
        assert_eq!(IntentType::Monitor.to_string(), "MONITOR");
    }
}
