"""Management command: dms_demo

Creates realistic sample DMS data (document types, repositories, folders,
documents, and document versions) for development and testing.

Usage
-----
  # Seed the first active tenant
  python manage.py dms_demo

  # Seed a specific tenant by slug
  python manage.py dms_demo --tenant solan

  # Clear existing DMS data first, then re-seed
  python manage.py dms_demo --reset
"""

from __future__ import annotations

import uuid
from datetime import timedelta

from django.contrib.auth import get_user_model
from django.core.management.base import BaseCommand, CommandError
from django.utils import timezone

User = get_user_model()


# ---------------------------------------------------------------------------
# Demo data specification
# ---------------------------------------------------------------------------

DOCUMENT_TYPES = [
    {"code": "contract",   "name": "قرارداد",          "icon": "TbFileContract",  "color": "#3B82F6"},
    {"code": "invoice",    "name": "فاکتور",            "icon": "TbFileInvoice",   "color": "#10B981"},
    {"code": "policy",     "name": "آیین‌نامه",         "icon": "TbFileText",      "color": "#8B5CF6"},
    {"code": "report",     "name": "گزارش",             "icon": "TbReport",        "color": "#F59E0B"},
    {"code": "memo",       "name": "یادداشت اداری",    "icon": "TbNotes",         "color": "#6B7280"},
    {"code": "proposal",   "name": "پیشنهادیه",        "icon": "TbPresentation",  "color": "#EC4899"},
    {"code": "hr_doc",     "name": "سند منابع انسانی", "icon": "TbUserCheck",     "color": "#14B8A6"},
    {"code": "technical",  "name": "سند فنی",           "icon": "TbCode",          "color": "#64748B"},
    {"code": "legal",      "name": "سند حقوقی",        "icon": "TbScale",         "color": "#DC2626"},
    {"code": "financial",  "name": "سند مالی",          "icon": "TbChartBar",      "color": "#059669"},
    {"code": "general",    "name": "عمومی",             "icon": "TbFile",          "color": "#9CA3AF"},
]

REPOSITORIES = [
    {
        "slug": "legal-docs",
        "name": "اسناد حقوقی",
        "description": "قراردادها، توافقنامه‌ها و اسناد حقوقی سازمان.",
        "is_default": False,
    },
    {
        "slug": "financial-docs",
        "name": "اسناد مالی",
        "description": "صورت‌های مالی، فاکتورها، بودجه و گزارش‌های مالی.",
        "is_default": True,
    },
    {
        "slug": "hr-docs",
        "name": "منابع انسانی",
        "description": "قراردادهای پرسنلی، رزومه‌ها و سوابق آموزشی.",
        "is_default": False,
    },
]

# Folders per repository: list of (name, parent_name_or_None)
FOLDERS = {
    "legal-docs": [
        ("قراردادها",      None),
        ("آراء و نظریات",  None),
        ("مکاتبات",        None),
        ("قراردادهای فروش", "قراردادها"),
        ("قراردادهای خرید", "قراردادها"),
    ],
    "financial-docs": [
        ("صورت‌های مالی",  None),
        ("فاکتورها",        None),
        ("بودجه",          None),
        ("گزارش‌های سالانه", "صورت‌های مالی"),
        ("گزارش‌های فصلی",  "صورت‌های مالی"),
    ],
    "hr-docs": [
        ("قراردادهای پرسنلی", None),
        ("آموزش و توسعه",     None),
        ("ارزیابی عملکرد",    None),
    ],
}

# Documents: (title, code, doc_type_code, repo_slug, folder_name_or_None, status, versions)
# versions: list of (label, change_summary, status, major, minor, days_ago)
DOCUMENTS = [
    # ---- Legal -------------------------------------------------------
    (
        "قرارداد همکاری با شرکت آلفا",
        "CONTRACT-1403-001",
        "contract",
        "legal-docs",
        "قراردادهای فروش",
        "published",
        [
            ("نسخه اولیه", "ایجاد قرارداد اولیه", "published", 1, 0, 30),
        ],
    ),
    (
        "قرارداد تامین مواد اولیه",
        "CONTRACT-1403-002",
        "contract",
        "legal-docs",
        "قراردادهای خرید",
        "published",
        [
            ("نسخه اولیه",      "ایجاد قرارداد",          "superseded", 1, 0, 60),
            ("ویرایش شرایط پرداخت", "به‌روزرسانی بند پرداخت", "published",  1, 1, 15),
        ],
    ),
    (
        "توافقنامه محرمانگی (NDA) با شریک تجاری",
        "CONTRACT-1403-003",
        "legal",
        "legal-docs",
        "قراردادها",
        "published",
        [
            ("نسخه اولیه", "ایجاد NDA", "published", 1, 0, 45),
        ],
    ),
    (
        "مکاتبه با اداره مالیات",
        "MEMO-1403-001",
        "memo",
        "legal-docs",
        "مکاتبات",
        "published",
        [
            ("نسخه ارسالی", "پاسخ به استعلام مالیاتی", "published", 1, 0, 20),
        ],
    ),
    (
        "پیش‌نویس قرارداد لیزینگ تجهیزات",
        "CONTRACT-1403-004",
        "contract",
        "legal-docs",
        "قراردادهای خرید",
        "draft",
        [
            ("پیش‌نویس اولیه", "ایجاد پیش‌نویس", "draft", 1, 0, 5),
        ],
    ),
    # ---- Financial ---------------------------------------------------
    (
        "صورت مالی سال ۱۴۰۲",
        "FIN-1402-ANNUAL",
        "financial",
        "financial-docs",
        "گزارش‌های سالانه",
        "published",
        [
            ("نسخه پیش‌نویس", "تهیه گزارش مالی",       "superseded", 1, 0, 180),
            ("نسخه نهایی",    "تایید حسابرس",           "published",  1, 1, 120),
        ],
    ),
    (
        "گزارش مالی فصل اول ۱۴۰۳",
        "FIN-1403-Q1",
        "financial",
        "financial-docs",
        "گزارش‌های فصلی",
        "published",
        [
            ("نسخه اولیه", "تهیه گزارش فصل اول", "published", 1, 0, 60),
        ],
    ),
    (
        "گزارش مالی فصل دوم ۱۴۰۳",
        "FIN-1403-Q2",
        "financial",
        "financial-docs",
        "گزارش‌های فصلی",
        "draft",
        [
            ("پیش‌نویس", "در حال تهیه گزارش فصل دوم", "draft", 1, 0, 3),
        ],
    ),
    (
        "بودجه سال ۱۴۰۳",
        "BUDGET-1403",
        "financial",
        "financial-docs",
        "بودجه",
        "published",
        [
            ("پیشنهاد اولیه",     "پیشنهاد بودجه توسط واحدها",   "superseded", 1, 0, 200),
            ("بازنگری اول",       "تجمیع و بازنگری",              "superseded", 1, 1, 180),
            ("تصویب هیئت مدیره", "بودجه تصویب‌شده نهایی",        "published",  2, 0, 150),
        ],
    ),
    (
        "فاکتور تامین‌کننده - شرکت پارت",
        "INV-1403-0042",
        "invoice",
        "financial-docs",
        "فاکتورها",
        "published",
        [
            ("فاکتور اصلی", "فاکتور دریافتی از تامین‌کننده", "published", 1, 0, 10),
        ],
    ),
    (
        "فاکتور خدمات نرم‌افزاری",
        "INV-1403-0051",
        "invoice",
        "financial-docs",
        "فاکتورها",
        "published",
        [
            ("فاکتور اصلی", "فاکتور ماهانه خدمات نرم‌افزار", "published", 1, 0, 7),
        ],
    ),
    (
        "گزارش حسابرسی داخلی ۱۴۰۳",
        "AUDIT-1403-01",
        "report",
        "financial-docs",
        "صورت‌های مالی",
        "published",
        [
            ("پیش‌نویس",    "گزارش اولیه حسابرسی",          "superseded", 1, 0, 90),
            ("نسخه نهایی", "ارائه به هیئت مدیره",           "published",  1, 1, 75),
        ],
    ),
    # ---- HR ----------------------------------------------------------
    (
        "قرارداد کار آقای احمدی",
        "HR-CONTRACT-001",
        "hr_doc",
        "hr-docs",
        "قراردادهای پرسنلی",
        "published",
        [
            ("قرارداد اولیه",     "استخدام رسمی",               "superseded", 1, 0, 730),
            ("تمدید قرارداد",     "تمدید یک‌ساله",              "published",  2, 0, 365),
        ],
    ),
    (
        "قرارداد کار خانم موسوی",
        "HR-CONTRACT-002",
        "hr_doc",
        "hr-docs",
        "قراردادهای پرسنلی",
        "published",
        [
            ("قرارداد اولیه", "استخدام به عنوان حسابدار", "published", 1, 0, 180),
        ],
    ),
    (
        "آیین‌نامه انضباطی سازمان",
        "HR-POLICY-001",
        "policy",
        "hr-docs",
        None,
        "published",
        [
            ("نسخه اولیه",   "تدوین آیین‌نامه انضباطی",           "superseded", 1, 0, 500),
            ("ویرایش ۱۴۰۲", "بازنگری و به‌روزرسانی",              "published",  1, 1, 300),
        ],
    ),
    (
        "برنامه آموزشی نیمه اول ۱۴۰۳",
        "HR-TRAINING-1403-H1",
        "hr_doc",
        "hr-docs",
        "آموزش و توسعه",
        "published",
        [
            ("طرح اولیه",   "پیشنهاد دوره‌های آموزشی",        "published", 1, 0, 120),
        ],
    ),
    (
        "گزارش ارزیابی عملکرد سالانه ۱۴۰۲",
        "HR-EVAL-1402",
        "report",
        "hr-docs",
        "ارزیابی عملکرد",
        "archived",
        [
            ("نسخه نهایی", "گزارش عملکرد سالانه", "archived", 1, 0, 400),
        ],
    ),
    (
        "پروپوزال پیاده‌سازی سیستم ERP",
        "PROP-1403-001",
        "proposal",
        "financial-docs",
        None,
        "draft",
        [
            ("پیش‌نویس اولیه", "ارزیابی اولیه و پروپوزال ERP", "draft", 1, 0, 8),
        ],
    ),
    (
        "مستندات فنی API مدیریت اسناد",
        "TECH-DMS-API-001",
        "technical",
        "legal-docs",
        None,
        "published",
        [
            ("نسخه ۱.۰", "مستندسازی اولیه API", "superseded", 1, 0, 90),
            ("نسخه ۱.۱", "افزودن endpoint های جدید", "published", 1, 1, 30),
        ],
    ),
    (
        "گزارش سالانه هیئت مدیره ۱۴۰۲",
        "REPORT-BOD-1402",
        "report",
        "financial-docs",
        "گزارش‌های سالانه",
        "published",
        [
            ("پیش‌نویس",    "تهیه گزارش سالانه",    "superseded", 1, 0, 320),
            ("نسخه نهایی", "تایید و انتشار",        "published",  1, 1, 280),
        ],
    ),
]


class Command(BaseCommand):
    help = "Seed realistic sample DMS data (repos, folders, documents, versions) for dev/test."

    def add_arguments(self, parser):
        parser.add_argument(
            "--tenant",
            dest="tenant_slug",
            default=None,
            help="Slug of the tenant to seed. Defaults to the first active tenant.",
        )
        parser.add_argument(
            "--reset",
            action="store_true",
            dest="reset",
            default=False,
            help="Delete existing DMS data for this tenant before seeding.",
        )

    def handle(self, *args, **options):
        from simorgh.apps.tenants.models import Tenant

        tenant_slug = options["tenant_slug"]
        reset = options["reset"]

        if tenant_slug:
            try:
                tenant = Tenant.objects.get(slug=tenant_slug)
            except Tenant.DoesNotExist:
                raise CommandError(f"Tenant {tenant_slug!r} not found.")
        else:
            tenant = Tenant.objects.filter(status="active").order_by("id").first()
            if not tenant:
                tenant = Tenant.objects.order_by("id").first()
            if not tenant:
                raise CommandError("No tenants found in the database.")

        self.stdout.write(f"Seeding DMS demo data for tenant: {tenant.slug!r}")

        if reset:
            self._reset_tenant(tenant)

        from simorgh.apps.organizations.models import OrganizationNode
        root_node = (
            OrganizationNode.objects.filter(tenant=tenant, parent__isnull=True)
            .order_by("id")
            .first()
        )
        if root_node is None:
            raise CommandError(f"Tenant {tenant.slug!r} has no root org node.")

        # Pick two users: a creator and an updater
        superuser = User.objects.filter(is_superuser=True).first()
        regular_user = User.objects.filter(is_superuser=False).order_by("id").first()
        creator = regular_user or superuser
        if creator is None:
            raise CommandError("No users found in the database.")

        # ---------- 1. Document types ----------
        doc_type_map = self._seed_document_types(tenant, root_node, creator)
        self.stdout.write(f"  DocumentTypes: {len(doc_type_map)} ready")

        # ---------- 2. Repositories ----------
        repo_map = self._seed_repositories(tenant, root_node, creator)
        self.stdout.write(f"  Repositories: {len(repo_map)} ready")

        # ---------- 3. Folders ----------
        folder_map = self._seed_folders(tenant, root_node, creator, repo_map)
        self.stdout.write(f"  Folders: {len(folder_map)} ready")

        # ---------- 4. Documents + versions ----------
        doc_count, ver_count = self._seed_documents(
            tenant, root_node, creator, doc_type_map, repo_map, folder_map
        )
        self.stdout.write(f"  Documents: {doc_count} ready, Versions: {ver_count} ready")

        self.stdout.write(self.style.SUCCESS("Done. DMS demo data loaded successfully."))

    # -----------------------------------------------------------------------

    def _reset_tenant(self, tenant):
        from simorgh.apps.dms.documents.models import DocumentVersion, Document, DocumentType
        from simorgh.apps.dms.repositories.models import Repository, Folder

        # Order matters due to FK constraints
        DocumentVersion.objects.filter(tenant=tenant).delete()
        Document.objects.filter(tenant=tenant).delete()
        Folder.objects.filter(tenant=tenant).delete()
        Repository.objects.filter(tenant=tenant).delete()
        DocumentType.objects.filter(tenant=tenant).delete()
        self.stdout.write(self.style.WARNING("  Existing DMS data cleared."))

    def _seed_document_types(self, tenant, org_node, creator):
        from simorgh.apps.dms.documents.models import DocumentType

        result = {}
        for spec in DOCUMENT_TYPES:
            obj, _ = DocumentType.objects.get_or_create(
                tenant=tenant,
                code=spec["code"],
                is_deleted=False,
                defaults={
                    "organization_node": org_node,
                    "name": spec["name"],
                    "icon": spec["icon"],
                    "color": spec["color"],
                    "description": "",
                    "is_active": True,
                    "created_by": creator,
                    "updated_by": creator,
                },
            )
            result[spec["code"]] = obj
        return result

    def _seed_repositories(self, tenant, org_node, creator):
        from simorgh.apps.dms.repositories.models import Repository

        result = {}
        for spec in REPOSITORIES:
            obj, _ = Repository.objects.get_or_create(
                tenant=tenant,
                slug=spec["slug"],
                is_deleted=False,
                defaults={
                    "organization_node": org_node,
                    "name": spec["name"],
                    "description": spec["description"],
                    "is_default": spec["is_default"],
                    "created_by": creator,
                    "updated_by": creator,
                },
            )
            result[spec["slug"]] = obj
        return result

    def _seed_folders(self, tenant, org_node, creator, repo_map):
        from simorgh.apps.dms.repositories.models import Folder

        result: dict[tuple[str, str], "Folder"] = {}  # (repo_slug, folder_name) -> Folder

        for repo_slug, folder_specs in FOLDERS.items():
            repo = repo_map.get(repo_slug)
            if repo is None:
                continue
            for name, parent_name in folder_specs:
                parent_obj = result.get((repo_slug, parent_name)) if parent_name else None
                depth = (parent_obj.depth + 1) if parent_obj else 0

                existing = Folder.objects.filter(
                    tenant=tenant,
                    repository=repo,
                    name=name,
                    is_deleted=False,
                ).first()
                if existing:
                    result[(repo_slug, name)] = existing
                    continue

                # Build materialized path after we have the pk
                folder = Folder(
                    tenant=tenant,
                    organization_node=org_node,
                    repository=repo,
                    parent=parent_obj,
                    name=name,
                    depth=depth,
                    sort_order=len(result),
                    created_by=creator,
                    updated_by=creator,
                )
                folder.save()

                # Set materialized path: parent_path + "/" + own_uuid  (or just own_uuid if root)
                own_uuid = str(folder.public_id)
                if parent_obj:
                    folder.materialized_path = parent_obj.materialized_path + "/" + own_uuid
                else:
                    folder.materialized_path = own_uuid
                folder.save(update_fields=["materialized_path"])

                result[(repo_slug, name)] = folder

        return result

    def _seed_documents(self, tenant, org_node, creator, doc_type_map, repo_map, folder_map):
        from simorgh.apps.dms.documents.models import Document, DocumentVersion, DocumentStatus, DocumentVersionStatus

        now = timezone.now()
        doc_count = 0
        ver_count = 0

        for (
            title, code, doc_type_code, repo_slug, folder_name,
            doc_status, version_specs
        ) in DOCUMENTS:
            repo = repo_map.get(repo_slug)
            if repo is None:
                continue
            folder = folder_map.get((repo_slug, folder_name)) if folder_name else None
            doc_type = doc_type_map.get(doc_type_code)

            # Skip if document with this code already exists
            if code and Document.objects.filter(tenant=tenant, code=code, is_deleted=False).exists():
                doc_count += 1
                ver_count += Document.objects.get(tenant=tenant, code=code, is_deleted=False).versions.count()
                continue

            doc = Document(
                tenant=tenant,
                organization_node=org_node,
                title=title,
                code=code,
                document_type=doc_type,
                repository=repo,
                folder=folder,
                status=doc_status,
                created_by=creator,
                updated_by=creator,
            )
            doc.save()
            doc_count += 1

            current_ver = None
            for label, change_summary, ver_status, major, minor, days_ago in version_specs:
                created_at = now - timedelta(days=days_ago)
                ver = DocumentVersion(
                    tenant=tenant,
                    organization_node=org_node,
                    document=doc,
                    label=label,
                    change_summary=change_summary,
                    status=ver_status,
                    version_major=major,
                    version_minor=minor,
                    is_current=(ver_status in (
                        DocumentVersionStatus.PUBLISHED,
                        DocumentVersionStatus.DRAFT,
                    )),
                    file_asset=None,
                    created_by=creator,
                    updated_by=creator,
                )
                # Override auto timestamps for realistic demo data
                ver.save()
                DocumentVersion.objects.filter(pk=ver.pk).update(
                    created_at=created_at,
                    updated_at=created_at,
                )
                ver_count += 1

                # The last non-superseded/non-archived version is current
                if ver_status in (DocumentVersionStatus.PUBLISHED, DocumentVersionStatus.DRAFT):
                    # Mark previous versions with is_current=False
                    if current_ver is not None:
                        DocumentVersion.objects.filter(pk=current_ver.pk).update(is_current=False)
                    current_ver = ver

            if current_ver:
                doc.current_version = current_ver
                doc.save(update_fields=["current_version"])

            # Sync timestamps on document too
            if version_specs:
                earliest_days = max(v[5] for v in version_specs)
                Document.objects.filter(pk=doc.pk).update(
                    created_at=now - timedelta(days=earliest_days),
                    updated_at=now - timedelta(days=version_specs[-1][5]),
                )

        return doc_count, ver_count
