use std::io::{self, BufRead, Write};

/// Interactive TUI (Text User Interface)
///
/// Simple CLI-based terminal interface for interactive questionnaires.
/// Provides user-friendly prompts without heavy dependencies.
///
/// Features:
/// - Text, select, multiselect, confirm, and number input modes
/// - Live validation with error messages
/// - Progress tracking
/// - Help text display
/// - Simple command-line interaction
use crate::questionnaire::questionnaire_engine::{
    Question, QuestionKind, QuestionnaireEngine, QuestionnaireResponse,
};

/// Interactive TUI for questionnaires
pub struct InteractiveTUI;

impl InteractiveTUI {
    /// Run interactive questionnaire session
    pub fn run(engine: &QuestionnaireEngine) -> io::Result<QuestionnaireResponse> {
        let stdin = io::stdin();
        let mut stdout = io::stdout();
        let mut reader = stdin.lock();
        let mut response =
            QuestionnaireResponse::new(engine.questionnaire_name(), engine.questionnaire_version());

        println!("\n╔════════════════════════════════════════════════╗");
        println!(
            "║ {} v{}",
            engine.questionnaire_name(),
            engine.questionnaire_version()
        );
        println!("╚════════════════════════════════════════════════╝\n");

        let mut current_question = engine.get_next_question(None, None, &response.answers);
        let mut question_count = 0;

        while let Some(question) = current_question {
            question_count += 1;
            let answer = Self::ask_question(&mut reader, &mut stdout, question, question_count)?;

            // Validate answer
            match engine.validate_answer(&question.id, &answer) {
                Ok(()) => {
                    response.add_answer(&question.id, answer.clone());

                    // Get next question
                    current_question = engine.get_next_question(
                        Some(&question.id),
                        Some(&answer),
                        &response.answers,
                    );
                }
                Err(err) => {
                    println!("  ✗ Validation error: {}\n", err);
                    continue;
                }
            }
        }

        println!("\n✓ Questionnaire complete!");
        Ok(response.complete())
    }

    fn ask_question(
        reader: &mut dyn BufRead,
        stdout: &mut dyn Write,
        question: &Question,
        question_number: usize,
    ) -> io::Result<String> {
        loop {
            println!("\n[Question {}/?]", question_number);
            println!("  {}", question.message);

            if let Some(help) = &question.help {
                println!("  ℹ {}", help);
            }

            match question.kind {
                QuestionKind::Text => {
                    Self::prompt_text(reader, stdout, question)?;
                }
                QuestionKind::Number => {
                    return Self::prompt_number(reader, stdout, question);
                }
                QuestionKind::Confirm => {
                    return Self::prompt_confirm(reader, stdout, question);
                }
                QuestionKind::Select => {
                    return Self::prompt_select(reader, stdout, question);
                }
                QuestionKind::Multiselect => {
                    return Self::prompt_multiselect(reader, stdout, question);
                }
            }

            let mut input = String::new();
            write!(stdout, "  > ")?;
            stdout.flush()?;
            reader.read_line(&mut input)?;
            let input = input.trim().to_string();

            if input.is_empty() && question.default.is_some() {
                return Ok(question.default.as_ref().unwrap().clone());
            }

            if !input.is_empty() {
                return Ok(input);
            }

            if question.validation.required {
                println!("  ✗ This field is required");
            }
        }
    }

    fn prompt_text(
        _reader: &mut dyn BufRead,
        _stdout: &mut dyn Write,
        question: &Question,
    ) -> io::Result<()> {
        if let Some(default) = &question.default {
            print!("  [{default}] > ");
        } else {
            print!("  > ");
        }
        io::stdout().flush()?;
        Ok(())
    }

    fn prompt_number(
        reader: &mut dyn BufRead,
        stdout: &mut dyn Write,
        question: &Question,
    ) -> io::Result<String> {
        if let Some(default) = &question.default {
            write!(stdout, "  [{default}] > ")?;
        } else {
            write!(stdout, "  > ")?;
        }
        stdout.flush()?;

        let mut input = String::new();
        reader.read_line(&mut input)?;
        let input = input.trim().to_string();

        if input.is_empty() && question.default.is_some() {
            return Ok(question.default.as_ref().unwrap().clone());
        }

        Ok(input)
    }

    fn prompt_confirm(
        reader: &mut dyn BufRead,
        stdout: &mut dyn Write,
        question: &Question,
    ) -> io::Result<String> {
        if let Some(default) = &question.default {
            write!(stdout, "  [{default}] (y/n) > ")?;
        } else {
            write!(stdout, "  (y/n) > ")?;
        }
        stdout.flush()?;

        let mut input = String::new();
        reader.read_line(&mut input)?;
        let input = input.trim().to_lowercase();

        match input.as_str() {
            "y" | "yes" => Ok("true".to_string()),
            "n" | "no" => Ok("false".to_string()),
            "" if question.default.is_some() => Ok(question.default.as_ref().unwrap().clone()),
            _ => Ok(input),
        }
    }

    fn prompt_select(
        reader: &mut dyn BufRead,
        stdout: &mut dyn Write,
        question: &Question,
    ) -> io::Result<String> {
        if let Some(choices) = &question.validation.choices {
            for (idx, choice) in choices.iter().enumerate() {
                writeln!(stdout, "  [{}] {}", idx + 1, choice)?;
            }
        }

        write!(stdout, "  Choose option: ")?;
        stdout.flush()?;

        let mut input = String::new();
        reader.read_line(&mut input)?;
        Ok(input.trim().to_string())
    }

    fn prompt_multiselect(
        reader: &mut dyn BufRead,
        stdout: &mut dyn Write,
        question: &Question,
    ) -> io::Result<String> {
        if let Some(choices) = &question.validation.choices {
            for (idx, choice) in choices.iter().enumerate() {
                writeln!(stdout, "  [{}] {}", idx + 1, choice)?;
            }
            writeln!(stdout, "  (Enter multiple options separated by commas)")?;
        }

        write!(stdout, "  Choose options: ")?;
        stdout.flush()?;

        let mut input = String::new();
        reader.read_line(&mut input)?;
        Ok(input.trim().to_string())
    }
}
// Helper methods for testing
impl InteractiveTUI {
    fn prompt_confirm_response(input: &str) -> String {
        match input.to_lowercase().as_str() {
            "y" | "yes" => "true".to_string(),
            "n" | "no" => "false".to_string(),
            _ => input.to_string(),
        }
    }
}

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

    #[test]
    fn test_confirm_response_parsing() {
        // Test that confirm responses are properly parsed
        assert_eq!(InteractiveTUI::prompt_confirm_response("y"), "true");
        assert_eq!(InteractiveTUI::prompt_confirm_response("n"), "false");
        assert_eq!(InteractiveTUI::prompt_confirm_response("yes"), "true");
        assert_eq!(InteractiveTUI::prompt_confirm_response("no"), "false");
    }
}
