"""
Command-line interface for YtQGen.

Usage:
    ytqgen process --input video.mp4 --output quiz.pdf
    ytqgen process --input https://youtube.com/watch?v=... --config config.yml
"""

import argparse
import sys
import os
from pathlib import Path
from typing import Optional

try:
    import yaml
    YAML_AVAILABLE = True
except ImportError:
    YAML_AVAILABLE = False

from . import __version__
# Don't import pipeline here - it will trigger config imports
# Import it after applying YAML config instead


def load_config(config_path: Optional[str]) -> dict:
    """Load configuration from YAML file."""
    if not config_path:
        return {}
    
    if not YAML_AVAILABLE:
        print("Warning: PyYAML not installed. Cannot load config file. Install with: pip install pyyaml")
        return {}
    
    try:
        with open(config_path, 'r', encoding='utf-8') as f:
            config = yaml.safe_load(f) or {}
        return config
    except Exception as e:
        print(f"Error loading config file {config_path}: {e}")
        return {}


def apply_config(config: dict) -> None:
    """Apply configuration settings to environment variables."""
    # Provider settings
    if 'provider' in config:
        os.environ['LLM_PROVIDER'] = config['provider']
    
    if 'transcription_provider' in config:
        os.environ['TRANSCRIPTION_PROVIDER'] = config['transcription_provider']
    
    # API keys
    if 'keys' in config:
        keys = config['keys']
        if 'openai' in keys:
            os.environ['OPENAI_API_KEY'] = keys['openai']
        if 'mistral' in keys:
            os.environ['MISTRAL_API_KEY'] = keys['mistral']
        if 'groq' in keys:
            os.environ['GROQ_API_KEY'] = keys['groq']
    
    # Model selection (Advanced - Optional)
    if 'models' in config:
        models = config['models']
        if 'openai' in models:
            os.environ['YTQGEN_OPENAI_MODEL'] = models['openai']
        if 'mistral' in models:
            os.environ['YTQGEN_MISTRAL_MODEL'] = models['mistral']
        if 'groq' in models:
            os.environ['YTQGEN_GROQ_MODEL'] = models['groq']
    
    # Generation settings (for future use)
    if 'generation' in config:
        gen = config['generation']
        if 'num_questions' in gen:
            os.environ['YTQGEN_NUM_QUESTIONS'] = str(gen['num_questions'])
        
        # Question type distribution
        if 'question_types' in gen:
            qt = gen['question_types']
            if 'mcq_percentage' in qt:
                os.environ['YTQGEN_MCQ_PERCENTAGE'] = str(qt['mcq_percentage'])
            if 'subjective_percentage' in qt:
                os.environ['YTQGEN_SUBJECTIVE_PERCENTAGE'] = str(qt['subjective_percentage'])
        
        # Difficulty distribution
        if 'difficulty' in gen:
            diff = gen['difficulty']
            if 'easy_percentage' in diff:
                os.environ['YTQGEN_EASY_PERCENTAGE'] = str(diff['easy_percentage'])
            if 'medium_percentage' in diff:
                os.environ['YTQGEN_MEDIUM_PERCENTAGE'] = str(diff['medium_percentage'])
            if 'hard_percentage' in diff:
                os.environ['YTQGEN_HARD_PERCENTAGE'] = str(diff['hard_percentage'])
        
        # Question style distribution
        if 'style' in gen:
            style = gen['style']
            if 'scenario_percentage' in style:
                os.environ['YTQGEN_SCENARIO_PERCENTAGE'] = str(style['scenario_percentage'])
            if 'theoretical_percentage' in style:
                os.environ['YTQGEN_THEORETICAL_PERCENTAGE'] = str(style['theoretical_percentage'])


def validate_config(config: dict) -> None:
    """Validate YAML configuration structure and values."""
    valid_providers = ["openai", "mistral", "groq"]
    
    # Valid model names for each provider
    valid_models = {
        "openai": ["gpt-4o-mini", "gpt-4", "gpt-4o", "gpt-3.5-turbo", "gpt-4-turbo"],
        "mistral": ["mistral-small-latest", "mistral-medium-latest", "mistral-large-latest", 
                    "mistral-small", "mistral-medium", "mistral-large"],
        "groq": ["openai/gpt-oss-20b", "openai/gpt-oss-120b", "llama-3.1-8b-instant"]
    }
    
    # Validate provider
    if "provider" in config:
        if config["provider"] not in valid_providers:
            raise ValueError(
                f"Invalid provider '{config['provider']}'. "
                f"Must be one of: {', '.join(valid_providers)}"
            )
    
    # Validate transcription provider
    if "transcription_provider" in config:
        if config["transcription_provider"] not in valid_providers:
            raise ValueError(
                f"Invalid transcription_provider '{config['transcription_provider']}'. "
                f"Must be one of: {', '.join(valid_providers)}"
            )
    
    # Validate keys structure
    if "keys" in config:
        if not isinstance(config["keys"], dict):
            raise ValueError("'keys' must be a dictionary")
    
    # Validate model selection
    if "models" in config:
        if not isinstance(config["models"], dict):
            raise ValueError("'models' must be a dictionary")
        
        models = config["models"]
        for provider, model_name in models.items():
            if provider not in valid_providers:
                print(f"Warning: Unknown provider '{provider}' in models section. Valid: {', '.join(valid_providers)}")
            elif model_name not in valid_models.get(provider, []):
                print(f"Warning: Model '{model_name}' may not be valid for {provider}. "
                      f"Common models: {', '.join(valid_models[provider][:3])}")
    
    # Validate generation settings
    if "generation" in config:
        gen = config["generation"]
        
        if "num_questions" in gen:
            if not isinstance(gen["num_questions"], int) or gen["num_questions"] <= 0:
                raise ValueError("'num_questions' must be a positive integer")
        
        # Validate question type percentages
        if "question_types" in gen:
            qt = gen["question_types"]
            mcq = qt.get("mcq_percentage", 0)
            subj = qt.get("subjective_percentage", 0)
            if mcq + subj != 100:
                raise ValueError(
                    f"Question type percentages must sum to 100 "
                    f"(got MCQ: {mcq}%, Subjective: {subj}%)"
                )
        
        # Validate difficulty percentages
        if "difficulty" in gen:
            diff = gen["difficulty"]
            easy = diff.get("easy_percentage", 0)
            medium = diff.get("medium_percentage", 0)
            hard = diff.get("hard_percentage", 0)
            if easy + medium + hard != 100:
                raise ValueError(
                    f"Difficulty percentages must sum to 100 "
                    f"(got Easy: {easy}%, Medium: {medium}%, Hard: {hard}%)"
                )
        
        # Validate style percentages
        if "style" in gen:
            style = gen["style"]
            scenario = style.get("scenario_percentage", 0)
            theoretical = style.get("theoretical_percentage", 0)
            if scenario + theoretical != 100:
                raise ValueError(
                    f"Style percentages must sum to 100 "
                    f"(got Scenario: {scenario}%, Theoretical: {theoretical}%)"
                )


def validate_api_keys() -> None:
    """Verify that required API keys are available."""
    providers_available = {
        'openai': os.getenv('OPENAI_API_KEY'),
        'mistral': os.getenv('MISTRAL_API_KEY'),
        'groq': os.getenv('GROQ_API_KEY'),
    }
    
    llm_provider = os.getenv('LLM_PROVIDER', 'openai').lower()
    trans_provider = os.getenv('TRANSCRIPTION_PROVIDER', 'openai').lower()
    
    # Check LLM provider
    if not providers_available.get(llm_provider):
        raise ValueError(
            f"API key missing for LLM provider '{llm_provider}'. "
            f"Set {llm_provider.upper()}_API_KEY in environment, .env file, or config YAML."
        )
    
    # Check transcription provider
    if not providers_available.get(trans_provider):
        raise ValueError(
            f"API key missing for transcription provider '{trans_provider}'. "
            f"Set {trans_provider.upper()}_API_KEY in environment, .env file, or config YAML."
        )
    
    print(f"✓ API keys validated for providers: {llm_provider}, {trans_provider}")


def validate_youtube_url(url: str) -> bool:
    """Validate that input is a YouTube URL."""
    youtube_domains = [
        'youtube.com',
        'www.youtube.com',
        'youtu.be',
        'm.youtube.com',
    ]
    
    url_lower = url.lower()
    is_youtube = any(domain in url_lower for domain in youtube_domains)
    
    if not is_youtube:
        raise ValueError(
            f"Invalid input: Only YouTube URLs are supported.\n"
            f"Got: {url}\n"
            f"Expected format: https://www.youtube.com/watch?v=VIDEO_ID"
        )
    
    return True


def cmd_process(args) -> int:
    """Process a YouTube video and generate questionnaire."""
    
    try:
        # Load config file FIRST (before any other imports that use config values)
        config = load_config(args.config)
        
        # Validate config structure
        if config:
            validate_config(config)
        
        # Apply config to environment BEFORE importing config module
        apply_config(config)
        
        # NOW import config values (after YAML has been applied)
        from .config import LLM_PROVIDER, TRANSCRIPTION_PROVIDER
        
        # Determine input and output (CLI overrides YAML)
        # Priority: CLI args > YAML config > defaults
        youtube_url = args.input or config.get('input')
        output_path = args.output or config.get('output') or "questionnaire.pdf"
        
        # Validate that we have an input
        if not youtube_url:
            print("Error: --input is required (or provide 'input' in YAML config)")
            print("\nUsage:")
            print("  ytqgen process --input <youtube_url> [--output <pdf_path>]")
            print("  ytqgen process --config config.yml  (with 'input' specified in YAML)")
            return 1
        
        # Override with CLI args if provided
        if args.provider:
            os.environ['LLM_PROVIDER'] = args.provider
        if args.transcription_provider:
            os.environ['TRANSCRIPTION_PROVIDER'] = args.transcription_provider
        if args.openai_key:
            os.environ['OPENAI_API_KEY'] = args.openai_key
        if args.mistral_key:
            os.environ['MISTRAL_API_KEY'] = args.mistral_key
        if args.groq_key:
            os.environ['GROQ_API_KEY'] = args.groq_key
        
        # Override generation settings from CLI
        if args.num_questions:
            os.environ['YTQGEN_NUM_QUESTIONS'] = str(args.num_questions)
        if args.mcq_percentage:
            os.environ['YTQGEN_MCQ_PERCENTAGE'] = str(args.mcq_percentage)
        if args.subjective_percentage:
            os.environ['YTQGEN_SUBJECTIVE_PERCENTAGE'] = str(args.subjective_percentage)
        
        # Validate YouTube URL
        validate_youtube_url(youtube_url)
        
        # Validate API keys
        validate_api_keys()
        
        print("=" * 70)
        print("YtQGen - YouTube to Questionnaire Generator")
        print("=" * 70)
        print(f"Version: {__version__}")
        print(f"YouTube URL: {youtube_url}")
        print(f"Output: {output_path}")
        print(f"LLM Provider: {LLM_PROVIDER}")
        print(f"Transcription Provider: {TRANSCRIPTION_PROVIDER}")
        print(f"Questions: {os.getenv('YTQGEN_NUM_QUESTIONS', '10')}")
        print(f"Distribution: {os.getenv('YTQGEN_MCQ_PERCENTAGE', '20')}% MCQ, "
              f"{os.getenv('YTQGEN_SUBJECTIVE_PERCENTAGE', '80')}% Subjective")
        if args.config:
            print(f"Config file: {args.config}")
        print("=" * 70)
        print()
        
        # Import pipeline AFTER config has been applied
        from .pipeline import process_stream
        
        # Process the stream
        result = process_stream(youtube_url, output_path)
        if result:
            print(f"\n✓ Success! Questionnaire saved to: {result}")
            return 0
        else:
            print("\n✗ Failed to generate questionnaire. Check the errors above.")
            return 1
            
    except ValueError as e:
        print(f"\n✗ Validation Error: {e}")
        return 1
    except KeyboardInterrupt:
        print("\n\nInterrupted by user.")
        return 130
    except Exception as e:
        print(f"\n✗ Unexpected error: {e}")
        import traceback
        traceback.print_exc()
        return 1


def cmd_version(args) -> int:
    """Print version information."""
    print(f"ytqgen {__version__}")
    return 0


def main():
    """Main entry point for the CLI."""
    parser = argparse.ArgumentParser(
        prog="ytqgen",
        description="Convert YouTube educational videos to interactive questionnaires",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
Examples:
  # Simple: Use config file for everything (input, output, API keys, settings)
  ytqgen process --config config.yml

  # CLI input with config file for API keys
  ytqgen process --input "https://youtube.com/watch?v=VIDEO_ID" --config config.yml

  # Override YAML config with CLI arguments
  ytqgen process --config config.yml --input "https://youtube.com/watch?v=OTHER_VIDEO" \\
      --output custom_quiz.pdf --num-questions 15

  # Full CLI mode (no config file needed if .env has API keys)
  ytqgen process --input "https://youtube.com/watch?v=VIDEO_ID" \\
      --provider openai --output my_quiz.pdf

  # Customize question distribution via CLI
  ytqgen process --input "https://youtube.com/watch?v=VIDEO_ID" \\
      --num-questions 20 --mcq-percentage 40 --subjective-percentage 60

  # Use different providers for LLM and transcription
  ytqgen process --input "https://youtube.com/watch?v=VIDEO_ID" \\
      --provider groq --transcription-provider mistral

Priority order (highest to lowest):
  CLI arguments > YAML config > .env file > environment variables

For more information, visit: https://github.com/AnubhavChoudhery/YtQGen
        """
    )
    
    parser.add_argument('--version', action='version', version=f'%(prog)s {__version__}')
    
    subparsers = parser.add_subparsers(dest='command', help='Available commands')
    
    # Process command
    process_parser = subparsers.add_parser('process', help='Process YouTube video and generate questionnaire')
    process_parser.add_argument(
        '--input', '-i',
        help='YouTube video URL (e.g., https://www.youtube.com/watch?v=VIDEO_ID). Can also be specified in YAML config.'
    )
    process_parser.add_argument(
        '--output', '-o',
        help='Output PDF file path (default: questionnaire.pdf or from YAML config)'
    )
    process_parser.add_argument(
        '--config', '-c',
        help='Path to YAML config file containing input, output, API keys, and settings'
    )
    process_parser.add_argument(
        '--provider',
        choices=['openai', 'mistral', 'groq'],
        help='LLM provider to use for summarization and question generation'
    )
    process_parser.add_argument(
        '--transcription-provider',
        choices=['openai', 'mistral', 'groq'],
        help='Provider to use for audio transcription'
    )
    process_parser.add_argument(
        '--openai-key',
        help='OpenAI API key (overrides config file and env var)'
    )
    process_parser.add_argument(
        '--mistral-key',
        help='Mistral API key (overrides config file and env var)'
    )
    process_parser.add_argument(
        '--groq-key',
        help='Groq API key (overrides config file and env var)'
    )
    process_parser.add_argument(
        '--num-questions',
        type=int,
        help='Number of questions to generate (default: 10)'
    )
    process_parser.add_argument(
        '--mcq-percentage',
        type=int,
        help='Percentage of MCQ questions (default: 20)'
    )
    process_parser.add_argument(
        '--subjective-percentage',
        type=int,
        help='Percentage of subjective questions (default: 80)'
    )
    process_parser.set_defaults(func=cmd_process)
    
    # Parse args
    args = parser.parse_args()
    
    if not args.command:
        parser.print_help()
        return 0
    
    # Execute command
    return args.func(args)


if __name__ == '__main__':
    sys.exit(main())
