//! Intelligent Question-Answering System Example
//!
//! This example demonstrates a comprehensive question-answering system that can handle
//! both context-based and general knowledge questions using HuggingFace models.
//!
//! The system includes:
//! - Context-aware question answering with document integration
//! - General knowledge question processing
//! - Multi-turn conversation support with context preservation
//! - Answer confidence scoring and quality assessment
//! - Knowledge base integration and management
//! - Interactive CLI interface for Q&A sessions
//! - Support for various question types and domains

#![allow(missing_docs)]
#![allow(clippy::missing_inline_in_public_items)]
#![allow(clippy::pedantic)]

use std::collections::HashMap;
use std::io::{self, Write};

use serde::{Deserialize, Serialize};

use api_huggingface::*;
use api_huggingface::components::input::InferenceParameters;
use api_huggingface::environment::HuggingFaceEnvironmentImpl;
use api_huggingface::secret::Secret;

/// Types of questions that can be answered
#[ derive( Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize ) ]
pub enum QuestionType
{
  /// Questions that require specific context to answer
  ContextBased,
  /// General knowledge questions
  GeneralKnowledge,
  /// Factual questions about specific topics
  Factual,
  /// Opinion-based questions
  Opinion,
  /// Yes/No questions
  YesNo,
  /// Multiple choice questions
  MultipleChoice,
}

impl QuestionType
{
  /// Get the appropriate model for this question type
  pub fn preferred_model(&self) -> &'static str
  {
  // Use Kimi-K2 model for all question types (new Router API)
  "moonshotai/Kimi-K2-Instruct-0905:groq"
  }

  /// Get the confidence threshold for this question type
  pub fn confidence_threshold(&self) -> f32
  {
  match self
  {
      Self::ContextBased => 0.8,      // High confidence needed for context-based answers
      Self::GeneralKnowledge => 0.7,  // Moderate confidence for general knowledge
      Self::Factual => 0.9,           // Very high confidence for facts
      Self::Opinion => 0.5,           // Lower confidence for opinions
      Self::YesNo => 0.8,             // High confidence for binary answers
      Self::MultipleChoice => 0.8,    // High confidence for multiple choice
  }
  }

  /// Get string representation for display
  pub fn as_str(&self) -> &'static str
  {
  match self
  {
      Self::ContextBased => "Context-based",
      Self::GeneralKnowledge => "General Knowledge",
      Self::Factual => "Factual",
      Self::Opinion => "Opinion",
      Self::YesNo => "Yes/No",
      Self::MultipleChoice => "Multiple Choice",
  }
  }
}

/// Difficulty levels for questions
#[ derive( Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize ) ]
pub enum DifficultyLevel
{
  Easy,
  Medium,
  Hard,
  Expert,
}

impl DifficultyLevel
{
  /// Get string representation for display
  pub fn as_str(&self) -> &'static str
  {
  match self
  {
      Self::Easy => "Easy",
      Self::Medium => "Medium",
      Self::Hard => "Hard",
      Self::Expert => "Expert",
  }
  }
}

/// Question with context and metadata
#[ derive( Debug, Clone, Serialize, Deserialize ) ]
pub struct Question
{
  pub id : String,
  pub text : String,
  pub question_type : QuestionType,
  pub difficulty : DifficultyLevel,
  pub context : Option< String >,
  pub expected_answer : Option< String >,
  pub keywords : Vec< String >,
  pub metadata : HashMap< String, String >,
}

impl Question
{
  /// Create a new question
  pub fn new(
  id : String,
  text : String,
  question_type : QuestionType,
  difficulty : DifficultyLevel,
  ) -> Self {
  Self {
      id,
      text,
      question_type,
      difficulty,
      context : None,
      expected_answer : None,
      keywords : Vec::new(),
      metadata : HashMap::new(),
  }
  }

  /// Add context to the question
  pub fn with_context(mut self, context : String) -> Self
  {
  self.context = Some(context);
  self
  }

  /// Add keywords to the question
  pub fn with_keywords(mut self, keywords : Vec< String >) -> Self
  {
  self.keywords = keywords;
  self
  }
}

/// Answer generated by the QA system
#[ derive( Debug, Clone, Serialize, Deserialize ) ]
pub struct Answer
{
  pub text : String,
  pub confidence : f32,
  pub sources : Vec< String >,
  pub reasoning : Option< String >,
  pub question_id : String,
  pub response_time_ms : u64,
}

/// Knowledge source for context-based questions
#[ derive( Debug, Clone, Serialize, Deserialize ) ]
pub struct KnowledgeSource
{
  pub id : String,
  pub title : String,
  pub content : String,
  pub source_type : SourceType,
  pub reliability_score : f32,
  pub last_updated : String,
  pub metadata : HashMap< String, String >,
}

impl KnowledgeSource
{
  /// Create a new knowledge source
  pub fn new(
  id : String,
  title : String,
  content : String,
  source_type : SourceType,
  reliability_score : f32,
  ) -> Self {
  Self {
      id,
      title,
      content,
      source_type,
      reliability_score,
      last_updated : chrono::Utc::now().format("%Y-%m-%d").to_string(),
      metadata : HashMap::new(),
  }
  }
}

/// Types of knowledge sources
#[ derive( Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize ) ]
pub enum SourceType
{
  Document,
  WebPage,
  Database,
  Manual,
  Encyclopedia,
  FAQ,
}

impl SourceType
{
  /// Get the reliability multiplier for this source type
  pub fn reliability_multiplier(&self) -> f32
  {
  match self
  {
      Self::Encyclopedia => 0.9,
      Self::Manual => 0.85,
      Self::Database => 0.8,
      Self::Document => 0.75,
      Self::WebPage => 0.6,
      Self::FAQ => 0.7,
  }
  }

  /// Get string representation for display
  pub fn as_str(&self) -> &'static str
  {
  match self
  {
      Self::Document => "Document",
      Self::WebPage => "Web Page",
      Self::Database => "Database",
      Self::Manual => "Manual",
      Self::Encyclopedia => "Encyclopedia",
      Self::FAQ => "FAQ",
  }
  }
}

/// Conversation turn in multi-turn QA
#[ derive( Debug, Clone, Serialize, Deserialize ) ]
pub struct ConversationTurn
{
  pub turn_id : usize,
  pub question : Question,
  pub answer : Option< Answer >,
  pub context_from_previous : Vec< String >,
}

/// Multi-turn conversation session
#[ derive( Debug, Clone, Serialize, Deserialize ) ]
pub struct QASession
{
  pub session_id : String,
  pub turns : Vec< ConversationTurn >,
  pub active_context : HashMap< String, String >,
  pub user_preferences : UserPreferences,
}

/// User preferences for QA responses
#[ derive( Debug, Clone, Serialize, Deserialize ) ]
pub struct UserPreferences
{
  pub preferred_length : AnswerLength,
  pub include_sources : bool,
  pub include_reasoning : bool,
  pub confidence_threshold : f32,
  pub preferred_topics : Vec< String >,
}

impl Default for UserPreferences
{
  fn default() -> Self
  {
  Self {
      preferred_length : AnswerLength::Standard,
      include_sources : false,
      include_reasoning : false,
      confidence_threshold : 0.6,
      preferred_topics : Vec::new(),
  }
  }
}

/// Desired answer length
#[ derive( Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize ) ]
pub enum AnswerLength
{
  Brief,     // 1-2 sentences
  Standard,  // 2-4 sentences
  Detailed,  // 4-8 sentences
  Comprehensive, // 8+ sentences
}

impl AnswerLength
{
  /// Get the word count range for this answer length
  pub fn word_count_range(&self) -> (usize, usize)
  {
  match self
  {
      Self::Brief => (10, 30),
      Self::Standard => (30, 80),
      Self::Detailed => (80, 150),
      Self::Comprehensive => (150, 300),
  }
  }

  /// Get the max tokens for this answer length
  pub fn max_tokens(&self) -> u32
  {
  match self
  {
      Self::Brief => 50u32,
      Self::Standard => 120u32,
      Self::Detailed => 200u32,
      Self::Comprehensive => 400u32,
  }
  }

  /// Get string representation for display
  pub fn as_str(&self) -> &'static str
  {
  match self
  {
      Self::Brief => "Brief",
      Self::Standard => "Standard", 
      Self::Detailed => "Detailed",
      Self::Comprehensive => "Comprehensive",
  }
  }
}

/// Question-answering system with knowledge base
#[ derive( Debug ) ]
pub struct QASystem
{
  pub client : Client< HuggingFaceEnvironmentImpl >,
  pub knowledge_sources : HashMap< String, KnowledgeSource >,
  pub active_sessions : HashMap< String, QASession >,
  pub default_model : String,
  pub accuracy_cache : HashMap< String, f32 >,
}

impl QASystem
{
  /// Create a new QA system
  pub fn new(client : Client< HuggingFaceEnvironmentImpl >) -> Self
  {
  Self {
      client,
      knowledge_sources : HashMap::new(),
      active_sessions : HashMap::new(),
      default_model : "moonshotai/Kimi-K2-Instruct-0905:groq".to_string(),
      accuracy_cache : HashMap::new(),
  }
  }

  /// Answer a single question
  pub async fn answer_question( &self, question : &Question ) -> Result< Answer, Box< dyn std::error::Error > >
  {
  let model = question.question_type.preferred_model();
  let prompt = Self::build_qa_prompt(question);
  
  let params = InferenceParameters::new()
      .with_temperature(0.3)  // Lower temperature for more consistent answers
      .with_max_new_tokens(Self::get_max_tokens_for_question(question))
      .with_top_p(0.8);

  let start_time = std::time::Instant::now();
  let result = self.client.inference().create_with_parameters(&prompt, model, params).await?;
  let response_time = start_time.elapsed().as_millis() as u64;
  
  let generated_text = result.extract_text_or_default( "" );
  
  let answer = Self::parse_answer(&generated_text, question, response_time)?;
  Ok(answer)
  }

  /// Start a new multi-turn QA session
  pub fn start_session(&mut self, session_id : String, preferences : UserPreferences) -> &QASession
  {
  let session = QASession {
      session_id : session_id.clone(),
      turns : Vec::new(),
      active_context : HashMap::new(),
      user_preferences : preferences,
  };

  self.active_sessions.insert(session_id.clone(), session);
  self.active_sessions.get(&session_id).unwrap()
  }

  /// Answer a question in the context of a session
  pub async fn answer_in_session( &mut self, session_id : &str, question : Question ) -> Result< Answer, Box< dyn std::error::Error > >
  {
  let session_context = if let Some(session) = self.active_sessions.get(session_id)
  {
      self.build_session_context(session)
  } else {
      String::new()
  };

  let mut context_question = question.clone();
  if !session_context.is_empty()
  {
      let prev_context = context_question.context.unwrap_or_default();
      context_question.context = Some(format!("{prev_context}\n\nPrevious context : {session_context}"));
  }

  let answer = self.answer_question(&context_question).await?;

  // Update session with new turn
  if let Some(session) = self.active_sessions.get_mut(session_id)
  {
      let turn = ConversationTurn {
  turn_id : session.turns.len(),
  question : context_question,
  answer : Some(answer.clone()),
  context_from_previous : Vec::new(), // Will be populated after turn creation
      };
      session.turns.push(turn);

      // Update active context
      let turn_num = session.turns.len() - 1;
      session.active_context.insert(format!("turn_{turn_num}"), answer.text.clone());
  }

  Ok(answer)
  }

  /// Add a knowledge source
  pub fn add_knowledge_source(&mut self, source : KnowledgeSource)
  {
  self.knowledge_sources.insert(source.id.clone(), source);
  }

  /// Search knowledge sources for relevant context
  pub fn search_knowledge_sources(&self, query : &str, max_results : usize) -> Vec< &KnowledgeSource >
  {
  let mut scored_sources : Vec< (&KnowledgeSource, f32) > = self.knowledge_sources
      .values()
      .map(|source| {
  let relevance = Self::calculate_relevance_score(query, source);
  (source, relevance)
      })
      .collect();

  scored_sources.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(core::cmp::Ordering::Equal));
  scored_sources.into_iter().take(max_results).map(|(source, _)| source).collect()
  }

  /// Evaluate answer accuracy against expected answer
  pub fn evaluate_accuracy(&self, generated_answer : &str, expected_answer : &str) -> f32
  {
  let generated_lower = generated_answer.to_lowercase();
  let expected_lower = expected_answer.to_lowercase();
  let generated_words = generated_lower.split_whitespace().collect::< Vec< _ > >();
  let expected_words = expected_lower.split_whitespace().collect::< Vec< _ > >();

  let common_words = generated_words.iter()
      .filter(|word| expected_words.contains(word))
      .count();

  if expected_words.is_empty()
  {
      return 0.0;
  }

  common_words as f32 / expected_words.len() as f32
  }

  /// Get system statistics
  pub fn get_system_stats(&self) -> QASystemStats
  {
  let total_questions_answered = self.active_sessions.values()
      .map(|session| session.turns.len())
      .sum();

  let avg_confidence = self.active_sessions.values()
      .flat_map(|session| session.turns.iter())
      .filter_map(|turn| turn.answer.as_ref().map(|a| a.confidence))
      .fold((0.0, 0), |(sum, count), conf| (sum + conf, count + 1));

  let average_confidence = if avg_confidence.1 > 0
  {
      avg_confidence.0 / avg_confidence.1 as f32
  } else {
      0.0
  };

  QASystemStats {
      total_knowledge_sources : self.knowledge_sources.len(),
      active_sessions : self.active_sessions.len(),
      total_questions_answered,
      average_confidence,
      cached_accuracies : self.accuracy_cache.len(),
  }
  }

  /// Build a prompt for question answering
  fn build_qa_prompt(question : &Question) -> String
  {
  use core::fmt::Write;
  let mut prompt = String::new();

  if let Some(context) = &question.context
  {
      let _ = write!(&mut prompt, "Context : {context}\n\n");
  }

  let _ = writeln!(&mut prompt, "Question : {}", question.text);
  
  match question.question_type
  {
      QuestionType::ContextBased => prompt.push_str("Answer based on the provided context:"),
      QuestionType::GeneralKnowledge => prompt.push_str("Answer based on general knowledge:"),
      QuestionType::Factual => prompt.push_str("Provide a factual answer:"),
      QuestionType::Opinion => prompt.push_str("Provide a balanced perspective:"),
      QuestionType::YesNo => prompt.push_str("Answer with Yes or No and explain briefly:"),
      QuestionType::MultipleChoice => prompt.push_str("Choose the best answer and explain:"),
  }

  prompt
  }

  /// Get appropriate max tokens for a question type
  fn get_max_tokens_for_question(question : &Question) -> u32
  {
  match question.difficulty
  {
      DifficultyLevel::Easy => 100u32,
      DifficultyLevel::Medium => 150u32,
      DifficultyLevel::Hard => 200u32,
      DifficultyLevel::Expert => 300u32,
  }
  }

  /// Parse the generated answer
  fn parse_answer( text : &str, question : &Question, response_time : u64 ) -> Result< Answer, Box< dyn std::error::Error > >
  {
  let cleaned_text = text.trim().to_string();
  let confidence = Self::calculate_confidence_score(&cleaned_text, question);
  
  Ok(Answer {
      text : cleaned_text,
      confidence,
      sources : Vec::new(), // Would be populated with actual source tracking
      reasoning : None,     // Would be extracted from response if available
      question_id : question.id.clone(),
      response_time_ms : response_time,
  })
  }

  /// Calculate confidence score for an answer
  fn calculate_confidence_score(answer : &str, question : &Question) -> f32
  {
  let mut confidence : f32 = 0.5; // Base confidence

  // Boost confidence based on answer characteristics
  if !answer.is_empty()
  {
      confidence += 0.2;
  }

  // Boost for appropriate length
  let word_count = answer.split_whitespace().count();
  if (5..=100).contains(&word_count)
  {
      confidence += 0.2;
  }

  // Boost for question-specific indicators
  match question.question_type
  {
      QuestionType::YesNo
  if answer.to_lowercase().contains("yes") || answer.to_lowercase().contains("no") =>
  {
          confidence += 0.1;
      },
      QuestionType::Factual
  if answer.contains('.') => // Proper sentences
  {
          confidence += 0.1;
      },
      _ => {}
  }

  confidence.min(1.0)
  }

  /// Build context from session history
  fn build_session_context(&self, session : &QASession) -> String
  {
  let recent_turns = session.turns.iter().rev().take(3).rev();
  let context_parts : Vec< String > = recent_turns
      .filter_map(|turn| {
  let q_text = &turn.question.text;
  turn.answer.as_ref().map(|a| {
          let a_text = &a.text;
          format!("Q: {q_text} A: {a_text}")
  })
      })
      .collect();
  
  context_parts.join("\n")
  }

  /// Calculate relevance score for knowledge source
  fn calculate_relevance_score(query : &str, source : &KnowledgeSource) -> f32
  {
  let query_lower = query.to_lowercase();
  let query_words = query_lower.split_whitespace().collect::< Vec< _ > >();
  let source_text = format!("{} {}", source.title.to_lowercase(), source.content.to_lowercase());
  
  let matches = query_words.iter()
      .filter(|word| source_text.contains(*word))
      .count();

  let base_score = if query_words.is_empty() { 0.0 } else { matches as f32 / query_words.len() as f32 };
  
  // Apply reliability multiplier
  base_score * source.source_type.reliability_multiplier() * source.reliability_score
  }
}

/// QA system statistics
#[ derive( Debug, Clone, Serialize, Deserialize ) ]
pub struct QASystemStats
{
  pub total_knowledge_sources : usize,
  pub active_sessions : usize,
  pub total_questions_answered : usize,
  pub average_confidence : f32,
  pub cached_accuracies : usize,
}

/// Interactive QA System Platform
#[ derive( Debug ) ]
pub struct QASystemPlatform
{
  qa_system : QASystem,
  current_session : Option< String >,
  stats : PlatformStats,
  sample_questions : Vec< Question >,
  sample_knowledge : Vec< KnowledgeSource >,
}

/// Platform usage statistics
#[ derive( Debug, Default ) ]
pub struct PlatformStats
{
  questions_asked : usize,
  sessions_created : usize,
  knowledge_sources_added : usize,
  total_response_time_ms : u64,
}

impl QASystemPlatform
{
  /// Create a new QA system platform
  pub fn new(client : Client< HuggingFaceEnvironmentImpl >) -> Self
  {
  let mut platform = Self {
      qa_system : QASystem::new(client),
      current_session : None,
      stats : PlatformStats::default(),
      sample_questions : Vec::new(),
      sample_knowledge : Vec::new(),
  };
  
  platform.load_sample_data();
  platform
  }

  /// Load sample questions and knowledge sources
  fn load_sample_data(&mut self)
  {
  // Load sample questions
  self.sample_questions = vec![
      Question::new(
  "q1".to_string(),
  "What is the capital of France?".to_string(),
  QuestionType::GeneralKnowledge,
  DifficultyLevel::Easy,
      ).with_keywords(vec!["capital".to_string(), "France".to_string()]),
      
      Question::new(
  "q2".to_string(),
  "Explain the benefits of renewable energy.".to_string(),
  QuestionType::ContextBased,
  DifficultyLevel::Medium,
      ).with_context("Renewable energy sources such as solar and wind power offer numerous benefits. They reduce greenhouse gas emissions, provide energy independence, and have lower long-term costs compared to fossil fuels.".to_string())
      .with_keywords(vec!["renewable".to_string(), "energy".to_string(), "benefits".to_string()]),
      
      Question::new(
  "q3".to_string(),
  "Is artificial intelligence beneficial for society?".to_string(),
  QuestionType::YesNo,
  DifficultyLevel::Hard,
      ).with_keywords(vec!["AI".to_string(), "society".to_string(), "beneficial".to_string()]),
      
      Question::new(
  "q4".to_string(),
  "What are the main components of a computer?".to_string(),
  QuestionType::Factual,
  DifficultyLevel::Medium,
      ).with_keywords(vec!["computer".to_string(), "components".to_string()]),
      
      Question::new(
  "q5".to_string(),
  "What do you think about remote work?".to_string(),
  QuestionType::Opinion,
  DifficultyLevel::Easy,
      ).with_keywords(vec!["remote".to_string(), "work".to_string(), "opinion".to_string()]),
  ];

  // Load sample knowledge sources
  self.sample_knowledge = vec![
      KnowledgeSource::new(
  "geo1".to_string(),
  "Geography Facts".to_string(),
  "Paris is the capital and largest city of France. It is located in the north of the country on the River Seine.".to_string(),
  SourceType::Encyclopedia,
  0.95,
      ),
      
      KnowledgeSource::new(
  "energy1".to_string(),
  "Renewable Energy Guide".to_string(),
  "Renewable energy technologies harness natural resources like sunlight, wind, and water to generate clean electricity without depleting resources or causing pollution.".to_string(),
  SourceType::Manual,
  0.9,
      ),
      
      KnowledgeSource::new(
  "tech1".to_string(),
  "Computer Components Manual".to_string(),
  "A computer typically consists of a CPU (Central Processing Unit), RAM (Random Access Memory), storage devices, motherboard, power supply, and input/output devices like keyboard and monitor.".to_string(),
  SourceType::Manual,
  0.88,
      ),
  ];

  // Add sample knowledge to the system
  for source in self.sample_knowledge.clone()
  {
      self.qa_system.add_knowledge_source(source);
      self.stats.knowledge_sources_added += 1;
  }
  }

  /// Run the interactive QA system
  pub async fn run(&mut self) -> Result< (), Box< dyn std::error::Error > >
  {
  println!("🧠 Intelligent Question-Answering System");
  println!("=====================================");
  println!();
  
  self.show_help();
  
  loop
  {
      print!("\n > ");
      io::stdout().flush()?;

      let mut input = String::new();
      io::stdin().read_line(&mut input)?;
      let input = input.trim();

      if input.is_empty()
      {
  continue;
      }

      match input
      {
  "/help" | "/h" => self.show_help(),
  "/quit" | "/q" => {
          println!("Thanks for using the QA system!");
          break;
  }
  "/session" => self.create_session_interactive()?,
  "/ask" => self.ask_question_interactive().await?,
  "/samples" => self.show_sample_questions(),
  "/knowledge" => self.manage_knowledge_interactive()?,
  "/stats" => self.show_statistics(),
  "/export" => self.export_session_interactive()?,
  cmd if cmd.starts_with('/') =>
  {
          println!("❌ Unknown command : {cmd}. Type /help for available commands.");
  }
  question => {
          // Direct question input
          self.answer_direct_question(question).await?;
  }
      }
  }

  Ok(())
  }

  /// Show help information
  fn show_help(&self)
  {
  println!("Available commands:");
  println!("  /ask        - Ask a question with options");
  println!("  /session    - Create or manage sessions");
  println!("  /samples    - Show sample questions");
  println!("  /knowledge  - Manage knowledge sources");
  println!("  /stats      - Show system statistics");
  println!("  /export     - Export session data");
  println!("  /help       - Show this help");
  println!("  /quit       - Exit the system");
  println!();
  println!("You can also type questions directly for quick answers.");
  println!("Example : What is machine learning?");
  }

  /// Handle direct question input
  async fn answer_direct_question(&mut self, question_text : &str) -> Result< (), Box< dyn std::error::Error > >
  {
  let q_num = self.stats.questions_asked;
  let question = Question::new(
      format!("direct_{q_num}"),
      question_text.to_string(),
      QuestionType::GeneralKnowledge,
      DifficultyLevel::Medium,
  );

  println!("\n🤔 Processing question...");
  
  let answer = if let Some(session_id) = &self.current_session.clone()
  {
      self.qa_system.answer_in_session(session_id, question).await?
  } else {
      self.qa_system.answer_question(&question).await?
  };

  Self::display_answer(&answer);
  self.update_stats(&answer);

  Ok(())
  }

  /// Interactive question asking
  async fn ask_question_interactive(&mut self) -> Result< (), Box< dyn std::error::Error > >
  {
  println!("\n📝 Ask a Question");
  println!("================");
  
  print!("Question : ");
  io::stdout().flush()?;
  let mut question_text = String::new();
  io::stdin().read_line(&mut question_text)?;
  let question_text = question_text.trim();

  if question_text.is_empty()
  {
      println!("❌ Question cannot be empty.");
      return Ok(());
  }

  // Select question type
  println!("\nQuestion types:");
  println!("1. General Knowledge");
  println!("2. Context-based");
  println!("3. Factual");
  println!("4. Opinion");
  println!("5. Yes/No");
  println!("6. Multiple Choice");
  
  print!("Select type (1-6): ");
  io::stdout().flush()?;
  let mut type_input = String::new();
  io::stdin().read_line(&mut type_input)?;
  
  let question_type = match type_input.trim()
  {
      "1" => QuestionType::GeneralKnowledge,
      "2" => QuestionType::ContextBased,
      "3" => QuestionType::Factual,
      "4" => QuestionType::Opinion,
      "5" => QuestionType::YesNo,
      "6" => QuestionType::MultipleChoice,
      _ => QuestionType::GeneralKnowledge,
  };

  // Select difficulty
  println!("\nDifficulty levels:");
  println!("1. Easy");
  println!("2. Medium");
  println!("3. Hard");
  println!("4. Expert");
  
  print!("Select difficulty (1-4): ");
  io::stdout().flush()?;
  let mut diff_input = String::new();
  io::stdin().read_line(&mut diff_input)?;
  
  let difficulty = match diff_input.trim()
  {
      "1" => DifficultyLevel::Easy,
      "2" => DifficultyLevel::Medium,
      "3" => DifficultyLevel::Hard,
      "4" => DifficultyLevel::Expert,
      _ => DifficultyLevel::Medium,
  };

  // Optional context
  let mut context = None;
  if question_type == QuestionType::ContextBased
  {
      print!("Context (optional): ");
      io::stdout().flush()?;
      let mut context_input = String::new();
      io::stdin().read_line(&mut context_input)?;
      let context_input = context_input.trim();
      if !context_input.is_empty()
      {
  context = Some(context_input.to_string());
      }
  }

  let q_num = self.stats.questions_asked;
  let mut question = Question::new(
      format!("custom_{q_num}"),
      question_text.to_string(),
      question_type,
      difficulty,
  );

  if let Some(ctx) = context
  {
      question = question.with_context(ctx);
  }

  let q_type_str = question_type.as_str();
  let diff_str = difficulty.as_str();
  println!("\n🤔 Processing {q_type_str} question with {diff_str} difficulty...");
  
  let answer = if let Some(session_id) = &self.current_session.clone()
  {
      self.qa_system.answer_in_session(session_id, question).await?
  } else {
      self.qa_system.answer_question(&question).await?
  };

  Self::display_answer(&answer);
  self.update_stats(&answer);

  Ok(())
  }

  /// Create or manage sessions
  fn create_session_interactive(&mut self) -> Result< (), Box< dyn std::error::Error > >
  {
  println!("\n🗣️  Session Management");
  println!("====================");
  
  if let Some(session_id) = &self.current_session
  {
      println!("Current session : {session_id}");
      println!("1. Continue with current session");
      println!("2. Create new session");
      println!("3. End current session");
  } else {
      println!("No active session");
      println!("1. Create new session");
      println!("2. Continue without session");
  }

  print!("Select option : ");
  io::stdout().flush()?;
  let mut option = String::new();
  io::stdin().read_line(&mut option)?;

  match option.trim()
  {
      "1" => {
  if self.current_session.is_none()
  {
          self.create_new_session()?;
  } else {
          println!("✅ Continuing with current session");
  }
      }
      "2" => {
  if self.current_session.is_some()
  {
          self.create_new_session()?;
  } else {
          println!("✅ Continuing without session (stateless mode)");
  }
      }
      "3" => {
  if self.current_session.is_some()
  {
          println!("✅ Session ended");
          self.current_session = None;
  }
      }
      _ => println!("❌ Invalid option"),
  }

  Ok(())
  }

  /// Create a new session
  fn create_new_session(&mut self) -> Result< (), Box< dyn std::error::Error > >
  {
  print!("Session name (optional): ");
  io::stdout().flush()?;
  let mut name = String::new();
  io::stdin().read_line(&mut name)?;
  let name = name.trim();

  let session_id = if name.is_empty()
  {
      let session_num = self.stats.sessions_created + 1;
      format!("session_{session_num}")
  } else {
      name.to_string()
  };

  let preferences = UserPreferences::default();
  self.qa_system.start_session(session_id.clone(), preferences);
  self.current_session = Some(session_id.clone());
  self.stats.sessions_created += 1;

  println!("✅ Created session : {session_id}");
  Ok(())
  }

  /// Show sample questions
  fn show_sample_questions(&self)
  {
  println!("\n📚 Sample Questions");
  println!("==================");
  
  for (i, question) in self.sample_questions.iter().enumerate()
  {
      let num = i + 1;
      let text = &question.text;
      let q_type = question.question_type.as_str();
      let diff = question.difficulty.as_str();
      println!("{num}. {text} [{q_type}] [{diff}]");
      
      if let Some(context) = &question.context
      {
  println!("   Context : {context}");
      }
  }

  println!("\nType the question number to ask it, or create your own with /ask");

  let max_num = self.sample_questions.len();
  print!("Select question (1-{max_num}) or press Enter to skip : ");
  io::stdout().flush().unwrap();
  
  let mut input = String::new();
  if io::stdin().read_line(&mut input).is_ok()
  {
      if let Ok(index) = input.trim().parse::< usize >()
      {
  if index > 0 && index <= self.sample_questions.len()
  {
          let question = self.sample_questions[index - 1].clone();
          tokio::spawn(async move {
      // Note : This is a simplified approach - in a real app you'd handle this better
      let q_text = &question.text;
      println!("Selected : {q_text}");
          });
  }
      }
  }
  }

  /// Manage knowledge sources
  fn manage_knowledge_interactive(&mut self) -> Result< (), Box< dyn std::error::Error > >
  {
  println!("\n📖 Knowledge Management");
  println!("======================");
  
  println!("1. View knowledge sources");
  println!("2. Add knowledge source");
  println!("3. Search knowledge sources");
  
  print!("Select option (1-3): ");
  io::stdout().flush()?;
  let mut option = String::new();
  io::stdin().read_line(&mut option)?;

  match option.trim()
  {
      "1" => self.view_knowledge_sources(),
      "2" => self.add_knowledge_source_interactive()?,
      "3" => self.search_knowledge_interactive()?,
      _ => println!("❌ Invalid option"),
  }

  Ok(())
  }

  /// View knowledge sources
  fn view_knowledge_sources(&self)
  {
  let source_count = self.qa_system.knowledge_sources.len();
  println!("\n📚 Knowledge Sources ({source_count}):");
  
  for (i, source) in self.qa_system.knowledge_sources.values().enumerate()
  {
      let num = i + 1;
      let title = &source.title;
      let s_type = source.source_type.as_str();
      let reliability = source.reliability_score;
      println!("{num}. {title} [{s_type}] (Reliability : {reliability:.2})");
      println!("   {}", &source.content[..source.content.len().min(100)]);
      if source.content.len() > 100
      {
  println!("   ...");
      }
  }
  }

  /// Add knowledge source interactively
  fn add_knowledge_source_interactive(&mut self) -> Result< (), Box< dyn std::error::Error > >
  {
  print!("Source title : ");
  io::stdout().flush()?;
  let mut title = String::new();
  io::stdin().read_line(&mut title)?;
  let title = title.trim().to_string();

  if title.is_empty()
  {
      println!("❌ Title cannot be empty.");
      return Ok(());
  }

  print!("Source content : ");
  io::stdout().flush()?;
  let mut content = String::new();
  io::stdin().read_line(&mut content)?;
  let content = content.trim().to_string();

  if content.is_empty()
  {
      println!("❌ Content cannot be empty.");
      return Ok(());
  }

  println!("Source types:");
  println!("1. Document");
  println!("2. Web Page");
  println!("3. Database");
  println!("4. Manual");
  println!("5. Encyclopedia");
  println!("6. FAQ");

  print!("Select source type (1-6): ");
  io::stdout().flush()?;
  let mut type_input = String::new();
  io::stdin().read_line(&mut type_input)?;

  let source_type = match type_input.trim()
  {
      "2" => SourceType::WebPage,
      "3" => SourceType::Database,
      "4" => SourceType::Manual,
      "5" => SourceType::Encyclopedia,
      "6" => SourceType::FAQ,
      _ => SourceType::Document, // Default for "1" and anything else
  };

  let source_num = self.stats.knowledge_sources_added;
  let source_id = format!("user_{source_num}");
  let source = KnowledgeSource::new(
      source_id,
      title,
      content,
      source_type,
      0.8, // Default reliability
  );

  self.qa_system.add_knowledge_source(source);
  self.stats.knowledge_sources_added += 1;

  println!("✅ Knowledge source added successfully!");
  Ok(())
  }

  /// Search knowledge sources interactively
  fn search_knowledge_interactive(&mut self) -> Result< (), Box< dyn std::error::Error > >
  {
  print!("Search query : ");
  io::stdout().flush()?;
  let mut query = String::new();
  io::stdin().read_line(&mut query)?;
  let query = query.trim();

  if query.is_empty()
  {
      println!("❌ Query cannot be empty.");
      return Ok(());
  }

  let results = self.qa_system.search_knowledge_sources(query, 5);
  
  if results.is_empty()
  {
      println!("❌ No relevant knowledge sources found.");
  } else {
      let result_count = results.len();
      println!("\n🔍 Search Results for '{query}' ({result_count} found):");
      for (i, source) in results.iter().enumerate()
      {
  let relevance = QASystem::calculate_relevance_score(query, source);
  let num = i + 1;
  let title = &source.title;
  let s_type = source.source_type.as_str();
  println!("{num}. {title} [{s_type}] (Relevance : {relevance:.2})");
  println!("   {}", &source.content[..source.content.len().min(150)]);
  if source.content.len() > 150
  {
          println!("   ...");
  }
      }
  }

  Ok(())
  }

  /// Show statistics
  fn show_statistics(&self)
  {
  let qa_stats = self.qa_system.get_system_stats();
  
  println!("\n📊 System Statistics");
  println!("===================");
  let q_asked = self.stats.questions_asked;
  let s_created = self.stats.sessions_created;
  let active_sess = qa_stats.active_sessions;
  let k_sources = qa_stats.total_knowledge_sources;
  let total_answered = qa_stats.total_questions_answered;
  let avg_conf = qa_stats.average_confidence;
  println!("Questions Asked : {q_asked}");
  println!("Sessions Created : {s_created}");
  println!("Active Sessions : {active_sess}");
  println!("Knowledge Sources : {k_sources}");
  println!("Total Questions Answered : {total_answered}");
  println!("Average Confidence : {avg_conf:.2}");
  let avg_time = if self.stats.questions_asked > 0
  {
      self.stats.total_response_time_ms as f64 / self.stats.questions_asked as f64
  } else {
      0.0
  };
  println!("Average Response Time : {avg_time:.2}ms");
  }

  /// Export session data
  fn export_session_interactive(&mut self) -> Result< (), Box< dyn std::error::Error > >
  {
  if let Some(session_id) = &self.current_session
  {
      if let Some(session) = self.qa_system.active_sessions.get(session_id)
      {
  let json_data = serde_json::to_string_pretty(session)?;
  
  print!("Export filename (press Enter for default): ");
  io::stdout().flush()?;
  let mut filename = String::new();
  io::stdin().read_line(&mut filename)?;
  let filename = filename.trim();
  
  let filename = if filename.is_empty()
  {
          format!("qa_session_{session_id}.json")
  } else {
          filename.to_string()
  };

  std::fs::write(&filename, json_data)?;
  println!("✅ Session exported to : {filename}");
      } else {
  println!("❌ Session not found");
      }
  } else {
      println!("❌ No active session to export");
  }
  
  Ok(())
  }

  /// Display answer with formatting
  fn display_answer(answer : &Answer)
  {
  println!("\n💡 Answer");
  println!("========");
  let text = &answer.text;
  println!("{text}");
  println!();
  let conf_pct = answer.confidence * 100.0;
  let resp_time = answer.response_time_ms;
  println!("Confidence : {conf_pct:.1}%");
  println!("Response Time : {resp_time}ms");
  
  if !answer.sources.is_empty()
  {
      let sources = answer.sources.join(", ");
      println!("Sources : {sources}");
  }
  
  if let Some(reasoning) = &answer.reasoning
  {
      println!("Reasoning : {reasoning}");
  }
  }

  /// Update platform statistics
  fn update_stats(&mut self, answer : &Answer)
  {
  self.stats.questions_asked += 1;
  self.stats.total_response_time_ms += answer.response_time_ms;
  }
}

#[ tokio::main ]
async fn main() -> Result< (), Box< dyn std::error::Error > >
{
  // Load API key from environment or workspace secrets
  let api_key = std::env::var("HUGGINGFACE_API_KEY")
  .or_else(|_| {
      use workspace_tools as workspace;
      let workspace = workspace::workspace()
  .map_err(|_| std::env::VarError::NotPresent)?; // Convert WorkspaceError
      let secrets = workspace.load_secrets_from_file("-secrets.sh")
  .map_err(|_| std::env::VarError::NotPresent)?; // Convert WorkspaceError
      secrets.get("HUGGINGFACE_API_KEY")
  .cloned()
  .ok_or(std::env::VarError::NotPresent)
  })?;

  // Initialize HuggingFace client
  let secret = Secret::new(api_key);
  let env = HuggingFaceEnvironmentImpl::build(secret, None)?;
  let client = Client::build(env)?;

  // Create and run the QA system platform
  let mut platform = QASystemPlatform::new(client);
  platform.run().await?;

  Ok(())
}