"""
Management command: migrate_legacy_rims2
=========================================
Orchestrates the full migration from the rims2 MySQL dump into IILMP.

Runs every migrate_legacy_* command in dependency order:

  Phase 1  — Institutions        (common_university)
  Phase 2  — Staff / Users       (contacts_user → role-mapped accounts)
  Phase 3  — Grant calls + apps  (calls_grantcall → GrantCall, grant applications, awards)
  Phase 4  — Scholarship calls   (calls_call → GrantCall type=scholarship)
  Phase 5  — Scholarship apps    (scholarships_scholarshipapplication + mastercard)
  Phase 6  — Fellowship apps     (fellowship_applications_fellowshipapplication)
  Phase 7  — Student chain       (contacts_student → Scholar + stipends)
  Phase 8  — Progress reports    (student_reports_studentreport + sub-tables)
  Phase 9  — Graduation records  (contacts_student.grad_actual → GraduationRecord)
  Phase 10 — P1 extras           (grant monthly reports, collaborators, fellowship profiles)

Usage:
    # Point at the rims2 dump container (port 3307 on host):
    docker compose run --rm -e LEGACY_DB_NAME=rims2 -e LEGACY_DB_PORT=3307 \\
        -e LEGACY_DB_PASSWORD=migrate123 \\
        web python manage.py migrate_legacy_rims2

    # Dry-run (no DB writes):
    docker compose run --rm -e LEGACY_DB_NAME=rims2 -e LEGACY_DB_PORT=3307 \\
        -e LEGACY_DB_PASSWORD=migrate123 \\
        web python manage.py migrate_legacy_rims2 --dry-run

    # Run specific phases only:
    docker compose run --rm -e LEGACY_DB_NAME=rims2 -e LEGACY_DB_PORT=3307 \\
        -e LEGACY_DB_PASSWORD=migrate123 \\
        web python manage.py migrate_legacy_rims2 --phases 1 2 3

    # Reset all migrated data first (use with caution):
    docker compose run --rm -e LEGACY_DB_NAME=rims2 -e LEGACY_DB_PORT=3307 \\
        -e LEGACY_DB_PASSWORD=migrate123 \\
        web python manage.py migrate_legacy_rims2 --reset

Environment variables (all optional, see apps/core/legacy_db.py):
    LEGACY_DB_HOST      (default: host.docker.internal)
    LEGACY_DB_PORT      (default: 3306)
    LEGACY_DB_NAME      (default: ruforum_rims_db)
    LEGACY_DB_USER      (default: root)
    LEGACY_DB_PASSWORD  (default: Joshua..123)
"""
from __future__ import annotations

import time

from django.core.management import call_command
from django.core.management.base import BaseCommand

from apps.core.legacy_db import LEGACY_DB


PHASES = [
    # (number, label, command, kwargs)
    (1,  "Institutions (common_university)",
         "migrate_legacy_grants",   {"phase": [1]}),
    (2,  "Staff & Users (contacts_user)",
         "migrate_legacy_staff",    {}),
    (3,  "Grant calls, applications & awards",
         "migrate_legacy_grants",   {"phase": [2, 3, 4, 5]}),
    (4,  "Scholarship calls (calls_call)",
         "migrate_legacy_scholarships", {"phase": ["A"]}),
    (5,  "Scholarship applications (standard + Mastercard)",
         "migrate_legacy_scholarships", {"phase": ["B", "C"]}),
    (6,  "Fellowship application profiles",
         "migrate_legacy_scholarships", {"phase": ["D", "E"]}),
    (7,  "Students → Scholars + stipends",
         "migrate_legacy_students",  {"phase": [1, 4]}),
    (8,  "Progress reports + sub-tables (manuscripts, conf. papers, etc.)",
         "migrate_legacy_students",  {"phase": [2]}),
    (9,  "Graduation records → Alumni profiles",
         "migrate_legacy_students",  {"phase": [3]}),
    (10, "P1 extras (monthly reports, collaborators, fellowship profiles)",
         "migrate_legacy_p1",        {"phase": [6, 7, 8, 9]}),
]


class Command(BaseCommand):
    help = "Full rims2 migration — runs all migrate_legacy_* commands in order."

    def add_arguments(self, parser):
        parser.add_argument(
            "--phases",
            nargs="*",
            type=int,
            default=None,
            help="Run only these phase numbers (e.g. --phases 1 2 3). Default: all.",
        )
        parser.add_argument(
            "--dry-run",
            action="store_true",
            help="Pass --dry-run to each sub-command (no DB writes).",
        )
        parser.add_argument(
            "--reset",
            action="store_true",
            help="Pass --reset to sub-commands that support it (wipes migrated data).",
        )
        parser.add_argument(
            "--fail-fast",
            action="store_true",
            help="Abort on first error instead of continuing.",
        )

    def handle(self, *args, **options):
        selected = set(options["phases"]) if options["phases"] else None
        dry_run  = options["dry_run"]
        reset    = options["reset"]
        fail_fast = options["fail_fast"]

        self.stdout.write(self.style.HTTP_INFO(
            f"\n{'='*60}\n"
            f"  migrate_legacy_rims2\n"
            f"  DB: {LEGACY_DB['user']}@{LEGACY_DB['host']}:{LEGACY_DB.get('port', 3306)}"
            f"/{LEGACY_DB['db']}\n"
            f"  dry_run={dry_run}  reset={reset}\n"
            f"{'='*60}"
        ))

        results = []
        total_start = time.time()

        for num, label, command, kwargs in PHASES:
            if selected and num not in selected:
                results.append((num, label, "skipped", 0))
                continue

            self.stdout.write(self.style.MIGRATE_HEADING(
                f"\n── Phase {num}: {label} ──"
            ))

            cmd_kwargs = dict(kwargs)
            if dry_run:
                cmd_kwargs["dry_run"] = True
            if reset and "reset" in _get_command_options(command):
                cmd_kwargs["reset"] = True

            t0 = time.time()
            try:
                call_command(command, **cmd_kwargs)
                elapsed = time.time() - t0
                results.append((num, label, "ok", elapsed))
                self.stdout.write(self.style.SUCCESS(
                    f"  ✓ Phase {num} done in {elapsed:.1f}s"
                ))
            except Exception as exc:  # noqa: BLE001
                elapsed = time.time() - t0
                results.append((num, label, f"FAILED: {exc}", elapsed))
                self.stdout.write(self.style.ERROR(
                    f"  ✗ Phase {num} FAILED in {elapsed:.1f}s: {exc}"
                ))
                if fail_fast:
                    raise

        total = time.time() - total_start
        self.stdout.write(self.style.MIGRATE_HEADING(
            f"\n{'='*60}\n"
            f"  Migration complete in {total:.1f}s\n"
            f"{'='*60}"
        ))
        for num, label, status, t in results:
            icon = "✓" if status == "ok" else ("↷" if status == "skipped" else "✗")
            self.stdout.write(f"  {icon} Phase {num:02d}: {label} — {status}" +
                              (f" ({t:.1f}s)" if status not in ("skipped",) else ""))


def _get_command_options(command_name: str) -> set[str]:
    """Return the option names accepted by a management command."""
    try:
        from django.core.management import load_command_class
        cmd = load_command_class("django.core", command_name)
        parser = cmd.create_parser("manage.py", command_name)
        return {a.dest for a in parser._actions}
    except Exception:  # noqa: BLE001
        return set()
