"""
AutoPIL admin CLI — catalog management and credential rotation.

Entry point: autopil-admin (console script defined in pyproject.toml)

Commands
--------
  catalog list-connections  [--tenant TENANT] [--db PATH] [--database-url URL]
  catalog test-connection   CONNECTION_ID [--db PATH] [--database-url URL]
  catalog force-sync        CONNECTION_ID [--db PATH] [--database-url URL]
  catalog rotate-key        [--old-key KEY] [--new-key KEY] [--dry-run]
                            [--db PATH] [--database-url URL]

Environment variables (override CLI defaults)
---------------------------------------------
  AUTOPIL_DB                      Path to SQLite DB (default: autopil_audit.db)
  DATABASE_URL                    Postgres connection URL (takes precedence over --db)
  AUTOPIL_CATALOG_ENCRYPTION_KEY  Current Fernet key for credential encryption
  AUTOPIL_CATALOG_ENCRYPTION_KEY_OLD  Previous key (accepted during rotation window)
"""

from __future__ import annotations

import argparse
import os
import sys
from pathlib import Path

DEFAULT_DB = "autopil_audit.db"


# ── helpers ───────────────────────────────────────────────────────────────────

def _get_catalog_store(args):
    database_url = getattr(args, "database_url", None) or os.environ.get("DATABASE_URL")
    db_path = getattr(args, "db", None) or os.environ.get("AUTOPIL_DB", DEFAULT_DB)
    try:
        from autopil.db import create_catalog_store
    except ImportError as exc:
        sys.exit(f"Error: {exc}")
    return create_catalog_store(database_url=database_url, db_path=db_path)


def _print_connection(conn, verbose: bool = False) -> None:
    status = "enabled" if conn.is_enabled else "disabled"
    last_sync = conn.last_sync_at.strftime("%Y-%m-%d %H:%M UTC") if conn.last_sync_at else "never"
    print(f"  {conn.connection_id}  [{conn.catalog_type}]  {conn.display_name}")
    print(f"    tenant={conn.tenant_id}  status={status}  sync_interval={conn.sync_interval_minutes}m  last_sync={last_sync}")
    if verbose:
        print(f"    base_url={conn.base_url}")
        print(f"    created={conn.created_at.strftime('%Y-%m-%d %H:%M UTC')}")


# ── subcommand handlers ───────────────────────────────────────────────────────

def cmd_list_connections(args) -> int:
    store = _get_catalog_store(args)
    tenant = getattr(args, "tenant", None)

    if tenant:
        connections = store.list_connections(tenant)
    else:
        connections = store.list_all_connections()

    if not connections:
        scope = f"tenant '{tenant}'" if tenant else "all tenants"
        print(f"No catalog connections found for {scope}.")
        return 0

    scope = f"tenant '{tenant}'" if tenant else "all tenants"
    print(f"\nCatalog connections ({scope}):\n")
    for conn in connections:
        _print_connection(conn, verbose=args.verbose)
        print()
    print(f"Total: {len(connections)}")
    return 0


def cmd_test_connection(args) -> int:
    store = _get_catalog_store(args)
    conn = None

    # Try all tenants if no tenant filter
    all_conns = store.list_all_connections()
    for c in all_conns:
        if c.connection_id == args.connection_id:
            conn = c
            break

    if not conn:
        print(f"Error: Connection '{args.connection_id}' not found.")
        return 1

    print(f"Testing connection '{conn.display_name}' ({conn.catalog_type}) ...")

    try:
        from autopil.catalog.registry import CatalogRegistry
        connector = CatalogRegistry.get_connector(conn)
        ok, msg = connector.test_connection()
    except Exception as exc:
        print(f"  FAIL — connector error: {exc}")
        return 1

    if ok:
        print("  OK")
        return 0
    else:
        print(f"  FAIL — {msg}")
        return 1


def cmd_force_sync(args) -> int:
    store = _get_catalog_store(args)
    all_conns = store.list_all_connections()
    conn = next((c for c in all_conns if c.connection_id == args.connection_id), None)

    if not conn:
        print(f"Error: Connection '{args.connection_id}' not found.")
        return 1

    print(f"Forcing sync for '{conn.display_name}' ({conn.catalog_type}) ...")

    try:
        from autopil.catalog.registry import CatalogRegistry
        from autopil.models import SyncResult
        import uuid
        from datetime import datetime

        connector = CatalogRegistry.get_connector(conn)
        started_at = datetime.utcnow()
        classifications = connector.fetch_classifications()
        completed_at = datetime.utcnow()

        if classifications:
            count = store.upsert_classifications(classifications)
            print(f"  Synced {count} classifications in {(completed_at - started_at).total_seconds():.1f}s")
        else:
            count = 0
            print(f"  Sync returned 0 classifications.")

        store.mark_sync_completed(conn.connection_id, completed_at)
        store.record_sync(SyncResult(
            sync_id=str(uuid.uuid4()),
            connection_id=conn.connection_id,
            tenant_id=conn.tenant_id,
            status="success",
            assets_synced=count,
            assets_skipped=0,
            started_at=started_at,
            completed_at=completed_at,
        ))
        return 0
    except Exception as exc:
        print(f"  FAIL — {exc}")
        return 1


def cmd_rotate_key(args) -> int:
    store = _get_catalog_store(args)

    old_key = getattr(args, "old_key", None) or os.environ.get("AUTOPIL_CATALOG_ENCRYPTION_KEY_OLD")
    new_key = getattr(args, "new_key", None) or os.environ.get("AUTOPIL_CATALOG_ENCRYPTION_KEY")
    dry_run = args.dry_run

    if not new_key:
        print(
            "Error: No new key provided.\n"
            "Set AUTOPIL_CATALOG_ENCRYPTION_KEY or pass --new-key.\n\n"
            "Generate a key with:\n"
            "  python -c \"from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())\""
        )
        return 1

    if dry_run:
        print("Dry-run mode — no changes will be written.\n")

    try:
        from autopil.catalog.credentials import rotate_encryption_key
        result = rotate_encryption_key(store, old_key=old_key, new_key=new_key, dry_run=dry_run)
    except NotImplementedError as exc:
        print(f"Error: {exc}")
        return 1
    except ValueError as exc:
        print(f"Error: {exc}")
        return 1
    except RuntimeError as exc:
        print(f"Rotation failed (rolled back): {exc}")
        return 1

    print(
        f"Key rotation {'(dry run) ' if dry_run else ''}complete:\n"
        f"  Rotated : {result['rotated']}\n"
        f"  Skipped : {result['skipped']}  (plaintext credentials — no key was set when registered)\n"
        f"  Failed  : {result['failed']}\n"
        f"  Total   : {result['total']}"
    )
    if not dry_run and result["rotated"] > 0:
        print(
            "\nNext steps:\n"
            "  1. Verify connections still work: autopil-admin catalog test-connection <id>\n"
            "  2. Remove AUTOPIL_CATALOG_ENCRYPTION_KEY_OLD from your environment."
        )
    return 0 if result["failed"] == 0 else 1


# ── argument parser ───────────────────────────────────────────────────────────

def _build_parser() -> argparse.ArgumentParser:
    parser = argparse.ArgumentParser(
        prog="autopil-admin",
        description="AutoPIL admin CLI — catalog management and credential rotation",
    )

    # Global options
    parser.add_argument(
        "--db",
        default=os.environ.get("AUTOPIL_DB", DEFAULT_DB),
        help="Path to SQLite audit DB (ignored if --database-url or DATABASE_URL is set)",
    )
    parser.add_argument(
        "--database-url",
        default=None,
        help="Postgres connection URL (overrides --db)",
    )

    subparsers = parser.add_subparsers(dest="resource", metavar="RESOURCE")

    # ── catalog subcommand group ──────────────────────────────────────────────
    catalog_parser = subparsers.add_parser("catalog", help="Manage catalog connections")
    catalog_sub = catalog_parser.add_subparsers(dest="action", metavar="ACTION")

    # list-connections
    list_p = catalog_sub.add_parser("list-connections", help="List all catalog connections")
    list_p.add_argument("--tenant", default=None, help="Filter by tenant ID")
    list_p.add_argument("--verbose", "-v", action="store_true", help="Show additional fields")

    # test-connection
    test_p = catalog_sub.add_parser("test-connection", help="Test a catalog connection live")
    test_p.add_argument("connection_id", help="Connection ID to test")

    # force-sync
    sync_p = catalog_sub.add_parser("force-sync", help="Immediately sync a catalog connection")
    sync_p.add_argument("connection_id", help="Connection ID to sync")

    # rotate-key
    rotate_p = catalog_sub.add_parser("rotate-key", help="Re-encrypt all credentials with a new key")
    rotate_p.add_argument("--old-key", default=None, help="Fernet key currently used (default: AUTOPIL_CATALOG_ENCRYPTION_KEY_OLD)")
    rotate_p.add_argument("--new-key", default=None, help="New Fernet key to encrypt with (default: AUTOPIL_CATALOG_ENCRYPTION_KEY)")
    rotate_p.add_argument("--dry-run", action="store_true", help="Verify decryption/re-encryption without writing changes")

    return parser


def main() -> None:
    parser = _build_parser()
    args = parser.parse_args()

    if args.resource is None:
        parser.print_help()
        sys.exit(0)

    if args.resource == "catalog":
        if args.action is None:
            # show catalog help
            parser.parse_args(["catalog", "--help"])
            sys.exit(0)

        handlers = {
            "list-connections": cmd_list_connections,
            "test-connection":  cmd_test_connection,
            "force-sync":       cmd_force_sync,
            "rotate-key":       cmd_rotate_key,
        }
        handler = handlers.get(args.action)
        if handler is None:
            parser.print_help()
            sys.exit(1)
        sys.exit(handler(args))
    else:
        parser.print_help()
        sys.exit(1)


if __name__ == "__main__":
    main()
