"""
Main entry point for IQToolkit Analyzer CLI
"""

import argparse
import logging
import sys
from pathlib import Path
from typing import Any, Dict, List, Optional, cast

# Initialize colorama for Windows terminal color support
try:
    import colorama

    colorama.init()
except ImportError:
    pass  # colorama is optional, won't break functionality

from .__version__ import __version__

logger = logging.getLogger(__name__)


def postgresql_command(args: argparse.Namespace) -> int:
    """Execute PostgreSQL slow query analysis."""
    from iqtoolkit_analyzer.analyzer import run_slow_query_analysis
    from iqtoolkit_analyzer.config import IQToolkitConfig
    from iqtoolkit_analyzer.llm_client import LLMClient, LLMConfig
    from iqtoolkit_analyzer.parser import (
        _resolve_existing_file,
        fetch_explain_plan_from_db,
        load_config,
        parse_explain_plan,
        parse_postgres_log,
    )
    from iqtoolkit_analyzer.report_generator import ReportGenerator

    if args.verbose:
        logging.basicConfig(
            level=logging.DEBUG,
            format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
        )
        logging.getLogger().setLevel(logging.DEBUG)
    else:
        setup_logging(
            args.log_level if hasattr(args, "log_level") else "INFO",
            args.log_file if hasattr(args, "log_file") else None,
        )

    logger = logging.getLogger(__name__)

    user_config = load_config(args.config)
    log_format = user_config.get("log_format") or "plain"
    configured_top_n = int(user_config.get("top_n") or args.top_n)
    configured_output = user_config.get("output") or args.output

    llm_defaults = LLMConfig()
    llm_config = LLMConfig(
        api_key=user_config.get("openai_api_key", llm_defaults.api_key),
        llm_provider=user_config.get("llm_provider", llm_defaults.llm_provider),
        openai_model=user_config.get("openai_model", llm_defaults.openai_model),
        ollama_model=user_config.get("ollama_model", llm_defaults.ollama_model),
        ollama_host=user_config.get("ollama_host", llm_defaults.ollama_host),
        vertex_model=user_config.get("vertex_model", llm_defaults.vertex_model),
        vertex_project=user_config.get("vertex_project", llm_defaults.vertex_project),
        vertex_region=user_config.get("vertex_region", llm_defaults.vertex_region),
        temperature=float(user_config.get("llm_temperature", llm_defaults.temperature)),
        max_tokens=int(user_config.get("max_tokens", llm_defaults.max_tokens)),
        timeout=int(user_config.get("llm_timeout", llm_defaults.timeout)),
    )

    try:
        target_desc = args.log_file or (args.query_file or "provided SQL")
        logger.info(f"Analyzing {target_desc}")

        # Parse logs, EXPLAIN file, or run EXPLAIN against a database
        if getattr(args, "plan", False):
            df = parse_explain_plan(args.log_file)
            configured_top_n = 1
        elif getattr(args, "sql", None) or getattr(args, "query_file", None):
            if not args.db_name:
                raise ValueError(
                    "--db-name is required when running SQL from config. "
                    "Add the database to ~/.iqtoolkit/config.yaml and pass --db-name."
                )

            config = IQToolkitConfig.load(args.config)
            db_cfg = config.get_database(args.db_name)
            if db_cfg is None:
                raise ValueError(
                    f"Database '{args.db_name}' not found in config. "
                    "Verify the name under databases: in ~/.iqtoolkit/config.yaml."
                )

            if (
                db_cfg.host is None
                or db_cfg.port is None
                or db_cfg.database is None
                or db_cfg.username is None
                or db_cfg.password is None
            ):
                raise ValueError(
                    f"Database '{args.db_name}' is missing required connection fields. "
                    "Ensure host, port, database, username, and password are set."
                )

            if args.query_file:
                query_path = _resolve_existing_file(args.query_file, purpose="SQL file")
                sql = query_path.read_text(encoding="utf-8")
            else:
                sql = args.sql

            host = str(db_cfg.host)
            port = int(db_cfg.port)
            dbname = str(db_cfg.database)
            username = str(db_cfg.username)
            password = str(db_cfg.password)

            df = fetch_explain_plan_from_db(
                host=host,
                port=port,
                dbname=dbname,
                user=username,
                password=password,
                sql=sql,
            )
            configured_top_n = 1
        else:
            if not args.log_file:
                raise ValueError(
                    "log_file is required unless --plan or --sql/--query-file "
                    "is provided. Provide a log file path or use --plan/--sql."
                )
            df = parse_postgres_log(args.log_file, log_format=log_format)

        if df.empty:
            logger.warning("No slow queries found")
            return 0

        # Analyze queries
        try:
            result = run_slow_query_analysis(df, top_n=configured_top_n)
        except ValueError as analysis_error:
            logger.warning(str(analysis_error))
            return 0

        # Type narrowing for DataFrame path
        if isinstance(result, tuple):
            top_queries, summary = result
            if len(top_queries) == 0:
                logger.warning("No slow queries met the analysis criteria")
                return 0
        else:
            logger.error("Unexpected return type from analysis")
            return 1

        # Generate AI recommendations
        logger.info("Generating recommendations...")
        llm_client = LLMClient(llm_config)

        queries_to_analyze: List[Dict[str, Any]] = []
        for row in top_queries.itertuples(index=False):
            queries_to_analyze.append(
                {
                    "query_text": str(row.example_query),
                    "avg_duration": float(cast(Any, row.avg_duration)),
                    "frequency": int(cast(Any, row.frequency)),
                    "explain_plan": str(row.explain_plan)
                    if hasattr(row, "explain_plan") and row.explain_plan
                    else None,
                }
            )

        recommendations = llm_client.batch_generate_recommendations(queries_to_analyze)

        from iqtoolkit_analyzer.analyzer import run_slow_query_analysis_contracts

        contract_results = run_slow_query_analysis_contracts(
            df,
            top_n=configured_top_n,
            provider=llm_config.llm_provider,
        )
        logger.debug(
            "Generated %d contract results from PostgreSQL analysis",
            len(contract_results),
        )

        # Generate report
        report_gen = ReportGenerator(llm_client)
        report = report_gen.generate_markdown_report(
            top_queries,
            summary,
            recommendations,
            contract_results=contract_results,
        )

        # Write output
        output_path = Path(configured_output)
        output_path.parent.mkdir(parents=True, exist_ok=True)
        output_path.write_text(report)

        print(f"✅ Report saved to: {output_path}")
        logger.info("Analysis complete!")
        return 0

    except FileNotFoundError as e:
        logger.error(f"File not found: {e}")
        return 1
    except Exception as e:
        logger.error(
            "Error: PostgreSQL analysis failed. "
            "Verify inputs and configuration. "
            f"Details: {e}"
        )
        return 1


def mongodb_command(args: argparse.Namespace) -> int:
    """Execute MongoDB slow query analysis."""
    from iqtoolkit_analyzer.mongodb_analyzer import MongoDBSlowQueryDetector
    from iqtoolkit_analyzer.mongodb_config import (
        MongoDBConnectionConfig,
        load_mongodb_config,
    )
    from iqtoolkit_analyzer.mongodb_report_generator import MongoDBReportGenerator

    try:
        # Load configuration
        config = load_mongodb_config(args.config)

        # Override connection string if provided via CLI
        if hasattr(args, "connection_string") and args.connection_string:
            if config.connection:
                config.connection.connection_string = args.connection_string
            else:
                config.connection = MongoDBConnectionConfig(
                    connection_string=args.connection_string
                )

        # Validate that we have a connection string
        if not config.get_effective_connection_string():
            print("Error: MongoDB connection string is required. Provide it via:")
            print("  --connection-string argument, or")
            print("  configuration file with connection settings")
            return 1

        # Setup logging
        if args.verbose:
            setup_logging("DEBUG", config.log_file)
        else:
            setup_logging(config.log_level, config.log_file)

        logger = logging.getLogger(__name__)

        logger.info("Starting MongoDB slow query analysis")
        logger.info(f"Target databases: {config.databases_to_monitor}")

        # Create detector
        connection_string = config.get_effective_connection_string()
        detector = MongoDBSlowQueryDetector(connection_string, config.thresholds)

        # Initialize detector
        if not detector.initialize():
            logger.error(
                "Failed to initialize MongoDB detector. "
                "Verify the connection string and credentials."
            )
            return 1

        # Start monitoring if requested
        if (
            hasattr(args, "enable_profiling")
            and args.enable_profiling
            and config.databases_to_monitor
        ):
            logger.info("Enabling profiling on target databases")
            if not detector.start_monitoring(config.databases_to_monitor):
                logger.warning("Failed to enable profiling on some databases")

        # Analyze each database
        all_reports = {}
        for database_name in config.databases_to_monitor or [args.database]:
            if not database_name:
                logger.error(
                    "No database specified for analysis. "
                    "Use --database or set databases_to_monitor in the config."
                )
                return 1

            logger.info(f"Analyzing database: {database_name}")

            # Generate comprehensive report
            skip_collection = (
                hasattr(args, "skip_collection_analysis")
                and args.skip_collection_analysis
            )
            report = detector.generate_comprehensive_report(
                database_name,
                include_collection_analysis=not skip_collection,
                include_contract_results=True,
            )

            contract_results = report.get("contract_results", [])
            if contract_results:
                logger.debug(
                    "Generated %d contract results for MongoDB %s",
                    len(contract_results),
                    database_name,
                )

            all_reports[database_name] = report

            # Print summary to console
            summary = report.get("summary", {})
            print(f"\n=== Analysis Summary for {database_name} ===")
            print(f"Slow Query Patterns: {summary.get('total_slow_queries', 0)}")
            print(f"Total Executions: {summary.get('total_executions', 0):,}")
            print(f"Average Duration: {summary.get('avg_duration_ms', 0):.1f}ms")
            print(f"Collections Affected: {summary.get('collections_affected', 0)}")
            print(
                f"Most Common Operation: {summary.get('most_common_operation', 'N/A')}"
            )

            # Show top recommendations
            recommendations = report.get("recommendations", [])
            if recommendations:
                print("\nTop Recommendations:")
                for i, rec in enumerate(recommendations[:3], 1):
                    print(f"{i}. {rec}")

        # Generate reports if output specified
        if args.output:
            output_dir = Path(args.output)
            output_dir.mkdir(parents=True, exist_ok=True)

            report_gen = MongoDBReportGenerator(config)
            for database_name, report in all_reports.items():
                # Generate requested formats
                for format_type in args.format:
                    if format_type == "html":
                        html_path = output_dir / f"{database_name}_report.html"
                        if report_gen.generate_html_report(report, str(html_path)):
                            print(f"✅ HTML report saved to: {html_path}")
                        else:
                            print("❌ Failed to generate")
                            print(f"HTML report for {database_name}")

                    elif format_type == "markdown":
                        md_path = output_dir / f"{database_name}_report.md"
                        if report_gen.generate_markdown_report(report, str(md_path)):
                            print(f"✅ Markdown report saved to: {md_path}")
                        else:
                            print("❌ Failed to generate")
                            print(f"Markdown report for {database_name}")

                    elif format_type == "json":
                        json_path = output_dir / f"{database_name}_report.json"
                        if report_gen.generate_json_report(report, str(json_path)):
                            print(f"✅ JSON report saved to: {json_path}")
                        else:
                            print("❌ Failed to generate JSON")
                            print(f"JSON report for {database_name}")

        return 0

    except Exception as e:
        logging.getLogger(__name__).error(
            "MongoDB analysis error. "
            "Check connection details and database name. "
            f"Details: {e}"
        )
        return 1


def setup_logging(level: str = "INFO", log_file: Optional[str] = None) -> None:
    """Configure logging"""
    log_level = getattr(logging, level.upper(), logging.INFO)

    handlers: List[logging.Handler] = [logging.StreamHandler()]
    if log_file:
        log_path = Path(log_file).expanduser()
        try:
            if log_path.parent and not log_path.parent.exists():
                log_path.parent.mkdir(parents=True, exist_ok=True)
            handlers.append(logging.FileHandler(log_path))
        except OSError as exc:
            logging.getLogger(__name__).warning(
                "Failed to initialize log file %s: %s", log_path, exc
            )

    logging.basicConfig(
        level=log_level,
        format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
        handlers=handlers,
    )


def serve_command(args: argparse.Namespace) -> int:
    """Execute the FastAPI server."""
    try:
        import uvicorn

        from iqtoolkit_analyzer.api.main import app

        uvicorn.run(app, host=args.host, port=args.port)
        return 0
    except ImportError:
        print("FastAPI server dependencies are missing.")
        print(
            "Reinstall IQToolkit Analyzer with its default dependencies (recommended). "
            "Try: pip install 'iqtoolkit-analyzer[api]'"
        )
        return 1
    except Exception as e:
        logger.error(
            "Failed to start server. "
            "Check host/port availability and dependencies. "
            f"Details: {e}"
        )
        return 1


def show_config_info() -> int:
    """Show configured databases and providers."""
    from iqtoolkit_analyzer.config import IQToolkitConfig

    config = IQToolkitConfig.load()
    issues = config.validate() if hasattr(config, "validate") else []

    databases = config.list_databases()
    providers = config.list_providers()

    if not databases and not providers:
        print("No configuration file found.")
        print("Create ~/.iqtoolkit/config.yaml to configure databases and providers.")
        return 0

    if databases:
        print("\n📦 Configured Databases:")
        for db_name in databases:
            db = config.get_database(db_name)
            if not db:
                continue
            print(f"  • {db_name}: {db.type} ({db.host}:{db.port}/{db.database})")

    if providers:
        print("\n🤖 Configured LLM Providers:")
        for provider_name in providers:
            provider = config.get_provider(provider_name)
            if not provider:
                continue
            print(f"  • {provider_name}: {provider.model}")

    if issues:
        print("\n⚠️ Configuration issues detected:")
        for issue in issues:
            print(f"  - {issue}")

    return 0


def validate_config(config_path: str) -> int:
    """Validate the IQToolkit config file."""
    from iqtoolkit_analyzer.config import IQToolkitConfig

    config = IQToolkitConfig.load(config_path)
    issues = config.validate() if hasattr(config, "validate") else []

    if not issues:
        print("✅ Configuration is valid")
        return 0

    print("❌ Configuration validation failed:")
    for issue in issues:
        print(f"  - {issue}")
    return 1


def main() -> int:
    """Main CLI function"""
    parser = argparse.ArgumentParser(
        description="IQToolkit Analyzer - AI-powered database performance analyzer",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
Examples:
  # Analyze PostgreSQL log file
  %(prog)s postgresql /path/to/slow.log

    # Analyze EXPLAIN (ANALYZE, FORMAT JSON) output
    %(prog)s postgresql --plan explain_output.json

    # Run EXPLAIN against configured database
    %(prog)s postgresql --db-name production \
        --sql "SELECT * FROM users WHERE id = 1"

    # Run EXPLAIN using a SQL file
    %(prog)s postgresql --db-name production \
        --query-file ./queries/slow_query.sql

  # Analyze MongoDB database with connection string
  %(prog)s mongodb --connection-string "mongodb://localhost:27017" --database myapp

  # Use MongoDB config file
  %(prog)s mongodb --config mongodb_config.yml

    # Enable MongoDB profiling before analysis
    %(prog)s mongodb --connection-string "mongodb://localhost:27017" \
        --database myapp --enable-profiling

    # Generate multiple report formats for MongoDB
    %(prog)s mongodb --connection-string "mongodb://localhost:27017" \
        --database myapp --output ./reports --format json html markdown

  # Generate HTML report for MongoDB
  %(prog)s mongodb --connection-string "mongodb://localhost:27017" \
    --output ./reports --format html

    # Show configured databases and providers
    %(prog)s config

    # Run the API server
    %(prog)s serve --host 0.0.0.0 --port 8000
        """,
    )

    parser.add_argument(
        "--version",
        action="version",
        version=f"%(prog)s {__version__}",
        help="Show version and exit",
    )

    parser.add_argument(
        "--verbose",
        action="store_true",
        help="Enable verbose (debug) output for troubleshooting and progress tracking.",
    )

    parser.add_argument(
        "--config",
        type=str,
        default=".iqtoolkit-analyzer.yml",
        help="Path to IQToolkit config file (default: .iqtoolkit-analyzer.yml)",
    )

    # Create subparsers for different database types
    subparsers = parser.add_subparsers(
        dest="database_type", help="Database type to analyze"
    )

    # PostgreSQL subcommand
    pg_parser = subparsers.add_parser(
        "postgresql",
        aliases=["pg", "postgres"],
        help="Analyze PostgreSQL slow query logs",
    )
    pg_parser.add_argument(
        "log_file",
        nargs="?",
        default=None,
        help="Path to PostgreSQL slow query log file",
    )
    pg_parser.add_argument(
        "--plan",
        action="store_true",
        help=(
            "Treat log_file as an EXPLAIN (ANALYZE, FORMAT JSON) output instead of a "
            "log"
        ),
    )
    pg_parser.add_argument(
        "--db-name",
        help="Database key from config to run EXPLAIN against (uses --config path)",
    )
    pg_parser.add_argument(
        "--query-file",
        help="Path to SQL file to EXPLAIN via configured database",
    )
    pg_parser.add_argument(
        "--sql",
        help="Inline SQL to EXPLAIN via configured database",
    )
    pg_parser.add_argument(
        "--output",
        type=str,
        default="reports/report.md",
        help="Output report path (default: reports/report.md)",
    )
    pg_parser.add_argument(
        "--top-n",
        type=int,
        default=5,
        help="Number of top slow queries to analyze (default: 5)",
    )

    # MongoDB subcommand
    mongo_parser = subparsers.add_parser(
        "mongodb", aliases=["mongo"], help="Analyze MongoDB slow queries"
    )
    mongo_parser.add_argument(
        "--connection-string",
        help="MongoDB connection string (e.g., 'mongodb://localhost:27017')",
    )
    mongo_parser.add_argument("--database", "-d", help="Database name to analyze")
    mongo_parser.add_argument(
        "--config", "-c", default=None, help="Configuration file path (YAML format)"
    )
    mongo_parser.add_argument("--output", "-o", help="Output directory for reports")
    mongo_parser.add_argument(
        "--format",
        "-f",
        choices=["json", "markdown", "html"],
        nargs="+",
        default=["json"],
        help="Report format(s) to generate",
    )
    mongo_parser.add_argument(
        "--enable-profiling",
        action="store_true",
        help="Enable MongoDB profiling before analysis",
    )
    mongo_parser.add_argument(
        "--skip-collection-analysis",
        action="store_true",
        help="Skip detailed collection-level analysis",
    )

    # Config subcommand
    config_parser = subparsers.add_parser(
        "config", help="Show configured databases and providers"
    )
    config_subparsers = config_parser.add_subparsers(dest="config_action")
    config_subparsers.add_parser("validate", help="Validate configuration")

    # Serve subcommand
    serve_parser = subparsers.add_parser("serve", help="Run the FastAPI server")
    serve_parser.add_argument(
        "--host",
        type=str,
        default="127.0.0.1",
        help="Host for the API server (default: 127.0.0.1)",
    )
    serve_parser.add_argument(
        "--port",
        type=int,
        default=8000,
        help="Port for the API server (default: 8000)",
    )

    # Parse arguments
    args = parser.parse_args()

    # Handle case where no subcommand is provided - show help
    if not args.database_type:
        parser.print_help()
        return 1

    # Dispatch to appropriate handler
    if args.database_type in ["postgresql", "pg", "postgres"]:
        return postgresql_command(args)
    elif args.database_type in ["mongodb", "mongo"]:
        return mongodb_command(args)
    elif args.database_type == "serve":
        return serve_command(args)
    elif args.database_type == "config":
        if getattr(args, "config_action", None) == "validate":
            return validate_config(args.config)
        return show_config_info()
    else:
        print(f"Unknown database type: {args.database_type}", file=sys.stderr)
        return 1


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