"""
CLI for the ReviewIQ pipeline.

Usage:
    reviewiq-pipeline migrate --database-url $DATABASE_URL
    reviewiq-pipeline run --job-id <UUID> --stages 1,2,3,4
    reviewiq-pipeline validate --job-id <UUID>
"""

from __future__ import annotations

import asyncio
import json
import logging
import sys
from typing import Any

import click

from reviewiq_pipeline import __version__

# Configure logging
logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
)
logger = logging.getLogger("reviewiq_pipeline")


def get_config(**overrides: Any):
    """Get configuration with optional overrides."""
    from reviewiq_pipeline.config import Config

    return Config(**{k: v for k, v in overrides.items() if v is not None})


@click.group()
@click.version_option(version=__version__)
def main():
    """ReviewIQ Pipeline - LLM-powered review classification."""
    pass


@main.command()
@click.option(
    "--database-url",
    envvar="DATABASE_URL",
    required=True,
    help="PostgreSQL connection string",
)
def migrate(database_url: str):
    """Run database migrations."""

    async def _migrate():
        from reviewiq_pipeline.db.connection import DatabasePool

        config = get_config(database_url=database_url)
        db = DatabasePool(config)

        try:
            await db.initialize()
            count = await db.run_migrations()
            click.echo(f"Successfully ran {count} migrations")
        except Exception as e:
            click.echo(f"Migration failed: {e}", err=True)
            sys.exit(1)
        finally:
            await db.close()

    asyncio.run(_migrate())


@main.command()
@click.option(
    "--job-id",
    required=True,
    help="Job ID to process",
)
@click.option(
    "--stages",
    default="1,2,3,4",
    help="Comma-separated list of stages to run (default: 1,2,3,4)",
)
@click.option(
    "--database-url",
    envvar="DATABASE_URL",
    required=True,
    help="PostgreSQL connection string",
)
@click.option(
    "--llm-provider",
    envvar="LLM_PROVIDER",
    type=click.Choice(["openai", "anthropic"]),
    default="openai",
    help="LLM provider",
)
@click.option(
    "--llm-model",
    envvar="LLM_MODEL",
    default="gpt-4o-mini",
    help="LLM model to use",
)
@click.option(
    "--openai-api-key",
    envvar="OPENAI_API_KEY",
    help="OpenAI API key",
)
@click.option(
    "--anthropic-api-key",
    envvar="ANTHROPIC_API_KEY",
    help="Anthropic API key",
)
@click.option(
    "--validate/--no-validate",
    default=True,
    help="Validate output after each stage",
)
@click.option(
    "--output",
    type=click.Path(),
    help="Output file for results (JSON)",
)
def run(
    job_id: str,
    stages: str,
    database_url: str,
    llm_provider: str,
    llm_model: str,
    openai_api_key: str | None,
    anthropic_api_key: str | None,
    validate: bool,
    output: str | None,
):
    """Run pipeline stages for a job."""

    async def _run():
        from reviewiq_pipeline import Pipeline

        # Parse stages
        stage_list = [int(s.strip()) for s in stages.split(",") if s.strip()]

        config = get_config(
            database_url=database_url,
            llm_provider=llm_provider,
            llm_model=llm_model,
            openai_api_key=openai_api_key,
            anthropic_api_key=anthropic_api_key,
        )

        pipeline = Pipeline(config)

        try:
            await pipeline.initialize()

            # Fetch job from database
            job_data = await pipeline._db.fetchrow(
                "SELECT * FROM jobs WHERE job_id = $1",
                job_id,
            )

            if not job_data:
                click.echo(f"Job {job_id} not found", err=True)
                sys.exit(1)

            # Build scraper output from job data
            reviews_data = job_data.get("reviews_data") or {}
            scraper_output = {
                "job_id": job_id,
                "status": job_data.get("status", "completed"),
                "business_id": reviews_data.get("business_id", job_id),
                "place_id": reviews_data.get("place_id", ""),
                "business_info": reviews_data.get("business_info", {}),
                "reviews": reviews_data.get("reviews", []),
                "scrape_time_ms": 0,
                "reviews_scraped": len(reviews_data.get("reviews", [])),
                "scraper_version": "v1.0.0",
            }

            # Run pipeline
            result = await pipeline.process(
                scraper_output,
                stages=stage_list,
                validate=validate,
            )

            # Output results
            if result.success:
                click.echo(click.style("Pipeline completed successfully!", fg="green"))
            else:
                click.echo(click.style("Pipeline completed with validation errors", fg="yellow"))

            # Print summary
            if result.stage1:
                click.echo(f"  Stage 1: {result.stage1['stats']['output_count']} reviews normalized")
            if result.stage2:
                click.echo(f"  Stage 2: {result.stage2['stats']['success_count']} reviews classified")
            if result.stage3:
                click.echo(f"  Stage 3: {result.stage3['stats']['spans_routed']} spans routed")
            if result.stage4:
                click.echo(f"  Stage 4: {result.stage4['stats']['facts_upserted']} facts written")

            # Validation summary
            for stage, validation in result.validation.items():
                status = "PASS" if validation["passed"] else f"FAIL ({validation['error_count']} errors)"
                click.echo(f"  {stage} validation: {status}")

            # Write output file
            if output:
                with open(output, "w") as f:
                    json.dump(result.to_dict(), f, indent=2, default=str)
                click.echo(f"Results written to {output}")

            if not result.success:
                sys.exit(1)

        except Exception as e:
            click.echo(f"Pipeline failed: {e}", err=True)
            logger.exception("Pipeline error")
            sys.exit(1)
        finally:
            await pipeline.close()

    asyncio.run(_run())


@main.command()
@click.option(
    "--job-id",
    required=True,
    help="Job ID to validate",
)
@click.option(
    "--database-url",
    envvar="DATABASE_URL",
    required=True,
    help="PostgreSQL connection string",
)
@click.option(
    "--stage",
    type=click.Choice(["1", "2", "3", "4", "all"]),
    default="all",
    help="Stage to validate (default: all)",
)
def validate(job_id: str, database_url: str, stage: str):
    """Validate pipeline output for a job."""

    async def _validate():
        from reviewiq_pipeline import Pipeline

        config = get_config(database_url=database_url)
        pipeline = Pipeline(config)

        try:
            await pipeline.initialize()

            results = await pipeline.validate(job_id)

            all_passed = True
            for stage_name, validation in results.items():
                if stage != "all" and f"stage{stage}" != stage_name:
                    continue

                status = "PASS" if validation["passed"] else "FAIL"
                color = "green" if validation["passed"] else "red"
                click.echo(click.style(f"{stage_name}: {status}", fg=color))

                if not validation["passed"]:
                    all_passed = False
                    for error in validation["errors"][:10]:
                        click.echo(f"  - [{error['rule']}] {error['identifier']}: {error['message']}")
                    if validation["error_count"] > 10:
                        click.echo(f"  ... and {validation['error_count'] - 10} more errors")

            if not all_passed:
                sys.exit(1)

        except Exception as e:
            click.echo(f"Validation failed: {e}", err=True)
            sys.exit(1)
        finally:
            await pipeline.close()

    asyncio.run(_validate())


@main.command()
@click.option(
    "--database-url",
    envvar="DATABASE_URL",
    required=True,
    help="PostgreSQL connection string",
)
def check(database_url: str):
    """Check database connection."""

    async def _check():
        from reviewiq_pipeline.db.connection import DatabasePool

        config = get_config(database_url=database_url)
        db = DatabasePool(config)

        try:
            await db.initialize()
            if await db.check_connection():
                click.echo(click.style("Database connection OK", fg="green"))
            else:
                click.echo(click.style("Database connection failed", fg="red"))
                sys.exit(1)
        finally:
            await db.close()

    asyncio.run(_check())


@main.command()
def version():
    """Show version information."""
    click.echo(f"reviewiq-pipeline {__version__}")


if __name__ == "__main__":
    main()
