"""
Create an isolated E2E hospital that mirrors a source hospital's org hierarchy,
plus 10 role-bound test users, for Playwright QA.

Mirrors (create-if-not-exists) from the source hospital (default HH-N / Al Nuzha):
  Area -> Department -> Section -> SubSection

LegacyLocation / LegacyMainSection / LegacySubSection are global reference tables
(shared by every hospital) and are intentionally NOT copied.

Department role-holders (champion/manager/supervisor) are left NULL on copy;
the E2E champion user is then bound as champion of one department.

Usage:
  uv run manage.py create_e2e_isolated_env --delete-existing
"""

from django.contrib.auth.models import Group
from django.core.management.base import BaseCommand
from django.db import transaction

from apps.accounts.models import User
from apps.organizations.models import (
    Area,
    Department,
    Hospital,
    Organization,
    Section,
    Staff,
    SubSection,
)
from apps.px_sources.models import PXSource, SourceUser

DEFAULT_PASSWORD = "Dev@123456"
DEFAULT_SOURCE_HOSPITAL_CODE = "HH-N"
E2E_ORG_CODE = "E2E-ORG"
E2E_HOSPITAL_CODE = "E2E-HOSP"
E2E_SOURCE_CODE = "E2E-TEST"

USERS_CONFIG = [
    {"email": "e2e-px-admin@px360.test", "role": "PX Admin", "first": "E2E", "last": "PX Admin", "is_champion": False, "source_profile": False},
    {"email": "e2e-hospital-admin@px360.test", "role": "Hospital Admin", "first": "E2E", "last": "Hospital Admin"},
    {"email": "e2e-dept-manager@px360.test", "role": "Department Manager", "first": "E2E", "last": "Dept Manager"},
    {"email": "e2e-px-employee@px360.test", "role": "PX Employee", "first": "E2E", "last": "PX Employee"},
    {"email": "e2e-physician@px360.test", "role": "Physician", "first": "E2E", "last": "Physician"},
    {"email": "e2e-nurse@px360.test", "role": "Nurse", "first": "E2E", "last": "Nurse"},
    {"email": "e2e-staff@px360.test", "role": "Staff", "first": "E2E", "last": "Staff"},
    {"email": "e2e-viewer@px360.test", "role": "Viewer", "first": "E2E", "last": "Viewer"},
    {"email": "e2e-source-user@px360.test", "role": "PX Source User", "first": "E2E", "last": "Source User", "source_profile": True},
    {"email": "e2e-champion@px360.test", "role": "Department Manager", "first": "E2E", "last": "Champion", "is_champion": True},
]


class Command(BaseCommand):
    help = "Create an isolated E2E hospital (mirrors source hospital hierarchy) + 10 role users"

    def add_arguments(self, parser):
        parser.add_argument("--password", default=DEFAULT_PASSWORD, help="Password for test users")
        parser.add_argument("--delete-existing", action="store_true", help="Delete existing E2E users + hospital first")
        parser.add_argument("--dry-run", action="store_true", help="Preview without changes")
        parser.add_argument("--source-hospital", default=DEFAULT_SOURCE_HOSPITAL_CODE, help="Source hospital code to mirror")

    @transaction.atomic()
    def handle(self, *args, **options):
        password = options["password"]
        delete_existing = options["delete_existing"]
        dry_run = options["dry_run"]
        source_code = options["source_hospital"]

        self.stdout.write(self.style.SUCCESS("\n=== Creating Isolated E2E Environment ===\n"))

        if dry_run:
            self.stdout.write(self.style.WARNING("DRY RUN - no changes\n"))

        source = Hospital.objects.filter(code=source_code).first()
        if not source:
            self.stdout.write(self.style.ERROR(f"Source hospital '{source_code}' not found."))
            return
        self.stdout.write(f"Source hospital: {source.name} ({source.code})")

        # ------------------------------------------------------------------
        # 0. Tear down existing E2E artifacts
        # ------------------------------------------------------------------
        if delete_existing and not dry_run:
            udel = User.objects.filter(email__endswith="@px360.test").delete()
            self.stdout.write(f"  Deleted {udel[0]} existing E2E user rows.")
            Hospital.objects.filter(code=E2E_HOSPITAL_CODE).delete()
            self.stdout.write("  Deleted existing E2E hospital (cascade removes mirrored hierarchy).")

        # ------------------------------------------------------------------
        # 1. Organization + Hospital
        # ------------------------------------------------------------------
        org, _ = Organization.objects.get_or_create(code=E2E_ORG_CODE, defaults={
            "name": "E2E Org",
            "name_ar": "بيئة الاختبار",
            "status": "active",
        })
        e2e, e2e_created = Hospital.objects.get_or_create(
            code=E2E_HOSPITAL_CODE,
            defaults={
                "organization": org,
                "name": "E2E Test Hospital",
                "name_ar": "مستشفى الاختبار",
                "display_name": "E2E Test Hospital",
                "status": "active",
            },
        )
        self.stdout.write(self.style.SUCCESS(f"  Hospital: {e2e.code} ({'created' if e2e_created else 'exists'})"))

        if dry_run:
            self.stdout.write(self.style.WARNING("\nDRY RUN - would mirror hierarchy + create users.\n"))
            return

        # ------------------------------------------------------------------
        # 2. Mirror hierarchy: Area -> Department -> Section -> SubSection
        # ------------------------------------------------------------------
        # Areas
        area_count = 0
        src_area_code_by_id = {}
        for a in Area.objects.filter(hospital=source):
            src_area_code_by_id[a.id] = a.code
            _, created = Area.objects.get_or_create(
                hospital=e2e, code=a.code,
                defaults={
                    "name_en": a.name_en, "name_ar": a.name_ar,
                    "location_type": a.location_type, "status": a.status,
                },
            )
            area_count += int(created)
        e2e_area_by_code = {a.code: a for a in Area.objects.filter(hospital=e2e)}
        self.stdout.write(self.style.SUCCESS(f"  Areas: +{area_count} new (total {len(e2e_area_by_code)})"))

        # Departments (pass 1: no parent; pass 2: link parent)
        dept_count = 0
        e2e_dept_by_code = {}
        for d in Department.objects.filter(hospital=source).select_related("area", "parent"):
            e2e_area = e2e_area_by_code.get(d.area.code) if d.area_id and d.area else None
            obj, created = Department.objects.get_or_create(
                hospital=e2e, code=d.code,
                defaults={
                    "name": d.name, "name_en": d.name_en, "name_ar": d.name_ar,
                    "hr_name": d.hr_name, "main_section": d.main_section,
                    "category": d.category, "location_type": d.location_type,
                    "sub_location": d.sub_location, "floor": d.floor,
                    "area": e2e_area, "phone": d.phone, "email": d.email,
                    "location": d.location, "status": d.status,
                    "old_name_en": d.old_name_en, "old_name_ar": d.old_name_ar,
                    "champion_email": d.champion_email,
                },
            )
            e2e_dept_by_code[d.code] = obj
            dept_count += int(created)
        # parents
        parent_count = 0
        for d in Department.objects.filter(hospital=source).select_related("parent"):
            if d.parent_id and d.parent.code in e2e_dept_by_code:
                e2e_obj = e2e_dept_by_code[d.code]
                e2e_parent = e2e_dept_by_code[d.parent.code]
                if e2e_obj.parent_id != e2e_parent.id:
                    e2e_obj.parent = e2e_parent
                    e2e_obj.save(update_fields=["parent"])
                    parent_count += 1
        self.stdout.write(self.style.SUCCESS(
            f"  Departments: +{dept_count} new, {parent_count} parents linked (total {len(e2e_dept_by_code)})"
        ))

        # Sections
        sect_count = 0
        e2e_sect_by_key = {}  # (dept_code, section_code) -> Section
        for s in Section.objects.filter(department__hospital=source).select_related("department"):
            e2e_dept = e2e_dept_by_code.get(s.department.code)
            if not e2e_dept:
                continue
            obj, created = Section.objects.get_or_create(
                department=e2e_dept, code=s.code,
                defaults={
                    "name_en": s.name_en, "name_ar": s.name_ar,
                    "location_type": s.location_type, "sub_location": s.sub_location,
                    "floor": s.floor, "display_name_en": s.display_name_en,
                    "display_name_ar": s.display_name_ar, "old_name_en": s.old_name_en,
                    "old_name_ar": s.old_name_ar, "status": s.status,
                },
            )
            e2e_sect_by_key[(s.department.code, s.code)] = obj
            sect_count += int(created)
        self.stdout.write(self.style.SUCCESS(f"  Sections: +{sect_count} new"))

        # SubSections
        sub_count = 0
        for ss in SubSection.objects.filter(section__department__hospital=source).select_related("section", "section__department"):
            key = (ss.section.department.code, ss.section.code)
            e2e_section = e2e_sect_by_key.get(key)
            if not e2e_section:
                continue
            _, created = SubSection.objects.get_or_create(
                section=e2e_section, code=ss.code,
                defaults={"name_en": ss.name_en, "name_ar": ss.name_ar, "status": ss.status},
            )
            sub_count += int(created)
        self.stdout.write(self.style.SUCCESS(f"  SubSections: +{sub_count} new"))

        # ------------------------------------------------------------------
        # 3. PXSource
        # ------------------------------------------------------------------
        px_source, _ = PXSource.objects.get_or_create(
            code=E2E_SOURCE_CODE,
            defaults={
                "name_en": "E2E Test Source",
                "name_ar": "مصدر اختبار E2E",
                "source_type": "internal",
                "contact_email": "e2e@px360.test",
                "is_active": True,
            },
        )

        # ------------------------------------------------------------------
        # 4. Users (bound to E2E hospital)
        # ------------------------------------------------------------------
        champion_user = None
        created_count = 0
        for cfg in USERS_CONFIG:
            email = cfg["email"]
            try:
                group = Group.objects.get(name=cfg["role"])
            except Group.DoesNotExist:
                self.stdout.write(self.style.WARNING(f"  SKIP {email}: group '{cfg['role']}' missing"))
                continue

            user, created = User.objects.get_or_create(
                email=email,
                defaults={
                    "first_name": cfg["first"],
                    "last_name": cfg["last"],
                    "hospital": e2e,
                    "is_active": True,
                    "is_staff": False,
                },
            )
            if created:
                user.set_password(password)
                created_count += 1
                self.stdout.write(self.style.SUCCESS(f"  CREATED: {email} ({cfg['role']})"))
            else:
                user.groups.clear()
                user.hospital = e2e
                self.stdout.write(f"  EXISTS:  {email} ({cfg['role']})")

            user.groups.add(group)
            user.save(update_fields=["hospital"]) if not created else user.save()

            if cfg.get("is_champion"):
                champion_user = user
            if cfg.get("source_profile"):
                SourceUser.objects.get_or_create(
                    user=user, source=px_source,
                    defaults={"is_active": True, "hospital": e2e},
                )

        # ------------------------------------------------------------------
        # 5. Bind champion user as champion of one department
        # ------------------------------------------------------------------
        if champion_user:
            champ_dept = Department.objects.filter(hospital=e2e).first()
            if champ_dept:
                champion_staff, _ = Staff.objects.get_or_create(
                    user=champion_user,
                    defaults={
                        "first_name": champion_user.first_name,
                        "last_name": champion_user.last_name,
                        "hospital": e2e,
                        "department": champ_dept,
                        "status": "active",
                        "staff_type": "admin",
                        "job_title": "Department Champion",
                        "employee_id": "E2E-CHAMPION",
                    },
                )
                champ_dept.champion = champion_staff
                champion_user.department = champ_dept
                champion_user.save(update_fields=["department"])

                # Bind dept-manager as department.manager of the SAME department
                # (so it can perform the manager-review step for this champion's responses)
                dm_user = User.objects.filter(email="e2e-dept-manager@px360.test").first()
                if dm_user:
                    dm_staff, _ = Staff.objects.get_or_create(
                        user=dm_user,
                        defaults={
                            "first_name": dm_user.first_name,
                            "last_name": dm_user.last_name,
                            "hospital": e2e,
                            "department": champ_dept,
                            "status": "active",
                            "staff_type": "admin",
                            "job_title": "Department Manager",
                            "employee_id": "E2E-DEPT-MGR",
                        },
                    )
                    champ_dept.manager = dm_user
                    dm_user.department = champ_dept
                    dm_user.save(update_fields=["department"])

                # Give e2e-staff a Staff profile in the SAME department (the
                # "involved/accused staff" the champion sends investigation questions to)
                st_user = User.objects.filter(email="e2e-staff@px360.test").first()
                if st_user:
                    Staff.objects.get_or_create(
                        user=st_user,
                        defaults={
                            "first_name": st_user.first_name,
                            "last_name": st_user.last_name,
                            "hospital": e2e,
                            "department": champ_dept,
                            "status": "active",
                            "staff_type": "other",
                            "job_title": "Staff",
                            "employee_id": "E2E-STAFF",
                        },
                    )
                    st_user.department = champ_dept
                    st_user.save(update_fields=["department"])

                champ_dept.save(update_fields=["champion", "manager"])
                self.stdout.write(self.style.SUCCESS(
                    f"  Champion/Manager/Staff bound to: {champ_dept.name_en or champ_dept.name}"
                ))

        self.stdout.write(self.style.SUCCESS(
            f"\nDone. Created {created_count} users. "
            f"Users total: {User.objects.filter(email__endswith='@px360.test').count()}"
        ))
        self.stdout.write(f"Hospital: {e2e.code} | "
                          f"Areas={Area.objects.filter(hospital=e2e).count()} "
                          f"Depts={Department.objects.filter(hospital=e2e).count()} "
                          f"Sections={Section.objects.filter(department__hospital=e2e).count()} "
                          f"SubSections={SubSection.objects.filter(section__department__hospital=e2e).count()}")
