"""
Management command to generate a drift report comparing YAML vs database.

Usage:
    # Generate report for all schemas
    python manage.py drift_report

    # Generate report for specific schema
    python manage.py drift_report --schema layouts

    # Output as JSON
    python manage.py drift_report --json

    # Save to file
    python manage.py drift_report --output drift-report.json
"""

import json
from datetime import datetime
from pathlib import Path

from django.core.management.base import BaseCommand, CommandError

from lightwave.schema import DriftStatus, reconcile
from lightwave.schema.loaders.base import SCHEMA_MODEL_MAP


class Command(BaseCommand):
    help = "Generate a drift report comparing YAML ideal state vs database reality"

    def add_arguments(self, parser):
        parser.add_argument(
            "--schema",
            type=str,
            help=f"Specific schema to report. Available: {', '.join(SCHEMA_MODEL_MAP.keys())}",
        )
        parser.add_argument(
            "--json",
            action="store_true",
            help="Output report as JSON",
        )
        parser.add_argument(
            "--output",
            "-o",
            type=str,
            help="Save report to file",
        )
        parser.add_argument(
            "--include-orphans",
            action="store_true",
            help="Include orphan items (in DB but not in YAML)",
        )

    def handle(self, *args, **options):
        schema_name = options.get("schema")
        output_json = options.get("json", False)
        output_file = options.get("output")
        include_orphans = options.get("include_orphans", False)

        # Determine which schemas to process
        if schema_name:
            if schema_name not in SCHEMA_MODEL_MAP:
                raise CommandError(f"Unknown schema '{schema_name}'. Available: {', '.join(SCHEMA_MODEL_MAP.keys())}")
            schemas = [schema_name]
        else:
            schemas = list(SCHEMA_MODEL_MAP.keys())

        all_reports = {}
        timestamp = datetime.now()

        self.stdout.write(f"\nGenerating drift report for {len(schemas)} schema(s)...\n")

        for name in schemas:
            try:
                report = reconcile(name, check_only=True)
                all_reports[name] = report
            except Exception as e:
                self.stdout.write(self.style.ERROR(f"❌ {name}: {e}"))

        # Build output
        if output_json or output_file:
            output_data = self._build_json_report(all_reports, timestamp, include_orphans)

            if output_file:
                path = Path(output_file)
                path.write_text(json.dumps(output_data, indent=2))
                self.stdout.write(self.style.SUCCESS(f"\nReport saved to: {path}"))
            else:
                self.stdout.write(json.dumps(output_data, indent=2))
        else:
            self._print_text_report(all_reports, timestamp, include_orphans)

    def _build_json_report(self, reports, timestamp, include_orphans):
        """Build JSON report structure."""
        output = {
            "generated_at": timestamp.isoformat(),
            "summary": {
                "total_schemas": len(reports),
                "clean_schemas": sum(1 for r in reports.values() if r.is_clean),
                "total_missing": sum(r.missing_count for r in reports.values()),
                "total_drift": sum(r.drift_count for r in reports.values()),
                "total_orphan": sum(r.orphan_count for r in reports.values()),
                "total_error": sum(r.error_count for r in reports.values()),
            },
            "schemas": {},
        }

        for name, report in reports.items():
            schema_data = {
                "is_clean": report.is_clean,
                "counts": {
                    "in_sync": report.in_sync_count,
                    "missing": report.missing_count,
                    "drift": report.drift_count,
                    "orphan": report.orphan_count,
                    "error": report.error_count,
                },
                "items": [],
            }

            for item in report.items:
                if item.status == DriftStatus.IN_SYNC:
                    continue
                if item.status == DriftStatus.ORPHAN and not include_orphans:
                    continue

                item_data = {
                    "status": item.status.value,
                    "key": item.key,
                }
                if item.diff_fields:
                    item_data["diff_fields"] = item.diff_fields
                if item.error:
                    item_data["error"] = item.error

                schema_data["items"].append(item_data)

            output["schemas"][name] = schema_data

        return output

    def _print_text_report(self, reports, timestamp, include_orphans):
        """Print human-readable text report."""
        self.stdout.write("=" * 60)
        self.stdout.write(f"DRIFT REPORT - {timestamp.strftime('%Y-%m-%d %H:%M:%S')}")
        self.stdout.write("=" * 60)

        total_missing = 0
        total_drift = 0
        total_orphan = 0
        total_error = 0

        for name, report in reports.items():
            total_missing += report.missing_count
            total_drift += report.drift_count
            total_orphan += report.orphan_count
            total_error += report.error_count

            self.stdout.write(f"\n{name.upper()}")
            self.stdout.write("-" * 40)

            if report.is_clean:
                self.stdout.write(self.style.SUCCESS(f"  ✅ {report.in_sync_count}/{report.total_items} in sync"))
            else:
                self.stdout.write(
                    f"  Total: {report.total_items} | "
                    f"In sync: {report.in_sync_count} | "
                    f"Missing: {report.missing_count} | "
                    f"Drift: {report.drift_count}"
                )
                if report.orphan_count and include_orphans:
                    self.stdout.write(f"  Orphan: {report.orphan_count}")
                if report.error_count:
                    self.stdout.write(f"  Errors: {report.error_count}")

                # Show details
                for item in report.needs_attention:
                    if item.status == DriftStatus.ORPHAN and not include_orphans:
                        continue

                    if item.status == DriftStatus.MISSING:
                        self.stdout.write(self.style.WARNING(f"  + MISSING: {item.key}"))
                        if item.yaml_value:
                            # Show key fields from YAML
                            preview = {
                                k: v
                                for k, v in item.yaml_value.items()
                                if k in ("name", "title", "path", "display_name")
                            }
                            if preview:
                                self.stdout.write(f"            YAML: {preview}")

                    elif item.status == DriftStatus.DRIFT:
                        self.stdout.write(self.style.WARNING(f"  ~ DRIFT: {item.key}"))
                        for field in item.diff_fields:
                            yaml_val = item.yaml_value.get(field) if item.yaml_value else "?"
                            db_val = item.db_value.get(field) if item.db_value else "?"
                            self.stdout.write(f"            {field}: YAML={yaml_val} | DB={db_val}")

                    elif item.status == DriftStatus.ORPHAN:
                        self.stdout.write(f"  ? ORPHAN: {item.key}")

                    elif item.status == DriftStatus.ERROR:
                        self.stdout.write(self.style.ERROR(f"  ✗ ERROR: {item.key} - {item.error}"))

        # Summary
        self.stdout.write("\n" + "=" * 60)
        self.stdout.write("SUMMARY")
        self.stdout.write("=" * 60)

        if total_missing == 0 and total_drift == 0 and total_error == 0:
            self.stdout.write(self.style.SUCCESS("\n✅ All schemas in sync with YAML definitions!"))
        else:
            if total_missing:
                self.stdout.write(self.style.WARNING(f"  ⚠️  {total_missing} items defined in YAML but missing from DB"))
            if total_drift:
                self.stdout.write(self.style.WARNING(f"  ⚠️  {total_drift} items with values different from YAML"))
            if total_orphan and include_orphans:
                self.stdout.write(f"  ❓ {total_orphan} items in DB but not defined in YAML")
            if total_error:
                self.stdout.write(self.style.ERROR(f"  ❌ {total_error} errors during comparison"))

            self.stdout.write("\nRun 'python manage.py reconcile' to sync DB with YAML.")
