"""Seed helpdesk module with default data.

Idempotent — safe to re-run at any time. All writes use ``update_or_create``
or ``get_or_create`` so manual adjustments in admin are preserved.

Usage
-----
    # Seed for every active tenant
    python manage.py seed_helpdesk

    # Seed only a specific tenant (by slug or pk)
    python manage.py seed_helpdesk --tenant acme
    python manage.py seed_helpdesk --tenant 3

Data seeded per tenant
----------------------
- 1 Default Queue
- 3 SLA Policies (basic, standard, premium)
- 6 Categories (general, billing, technical, account, onboarding, other)
- 10 Tags (bug, feature-request, urgent, billing, account, integration,
          performance, security, documentation, feedback)
- 5 Default Process Definitions (via .seed/processes.json, registered in workflow engine)
- IAM roles via stdout reminder (roles belong to IAM, not helpdesk)
"""

from __future__ import annotations

import json
import logging
import os
import sys
from typing import Any

from django.core.management.base import BaseCommand, CommandError
from django.db import transaction

_log = logging.getLogger("simorgh.helpdesk")


# ---------------------------------------------------------------------------
# Seed data definitions
# ---------------------------------------------------------------------------

DEFAULT_QUEUE = {
    "name": "General Support",
    "description": "Default queue for all incoming support requests.",
    "email_address": "",
    "is_default": True,
    "is_active": True,
    "sort_order": 10,
}

SLA_POLICIES: list[dict[str, Any]] = [
    {
        "name": "Basic SLA",
        "description": "Best-effort response within one business day.",
        "first_response_hours": 24,
        "resolution_hours": 72,
        "is_active": True,
    },
    {
        "name": "Standard SLA",
        "description": "Standard 4-hour first response with 24-hour resolution.",
        "first_response_hours": 4,
        "resolution_hours": 24,
        "is_active": True,
    },
    {
        "name": "Premium SLA",
        "description": "Premium 1-hour first response with 8-hour resolution.",
        "first_response_hours": 1,
        "resolution_hours": 8,
        "is_active": True,
    },
]

CATEGORIES: list[dict[str, Any]] = [
    {
        "name": "General",
        "description": "General inquiries and requests.",
        "sort_order": 10,
        "children": [
            {"name": "Question", "description": "General question or information request.", "sort_order": 10},
            {"name": "Feedback", "description": "General feedback or suggestion.", "sort_order": 20},
            {"name": "Complaint", "description": "General complaint.", "sort_order": 30},
        ],
    },
    {
        "name": "Billing",
        "description": "Billing, invoicing and payment issues.",
        "sort_order": 20,
        "children": [
            {"name": "Invoice Issue", "description": "Incorrect or missing invoice.", "sort_order": 10},
            {"name": "Payment Problem", "description": "Payment failed or not processed.", "sort_order": 20},
            {"name": "Refund Request", "description": "Request for a refund.", "sort_order": 30},
            {"name": "Subscription Change", "description": "Upgrade, downgrade or cancellation.", "sort_order": 40},
        ],
    },
    {
        "name": "Technical",
        "description": "Technical support and troubleshooting.",
        "sort_order": 30,
        "children": [
            {"name": "Bug Report", "description": "Something is broken or not working as expected.", "sort_order": 10},
            {"name": "Performance Issue", "description": "Slow response or timeout errors.", "sort_order": 20},
            {"name": "Integration Problem", "description": "Issue with API or third-party integration.", "sort_order": 30},
            {"name": "Data Issue", "description": "Incorrect, missing or corrupted data.", "sort_order": 40},
        ],
    },
    {
        "name": "Account",
        "description": "Account access, settings and security.",
        "sort_order": 40,
        "children": [
            {"name": "Login / Access", "description": "Cannot log in or access account.", "sort_order": 10},
            {"name": "Password Reset", "description": "Forgotten or expired password.", "sort_order": 20},
            {"name": "Profile Update", "description": "Change of name, email or contact info.", "sort_order": 30},
            {"name": "Security Concern", "description": "Suspicious activity or security issue.", "sort_order": 40},
        ],
    },
    {
        "name": "Onboarding",
        "description": "Help getting started and initial setup.",
        "sort_order": 50,
        "children": [
            {"name": "Initial Setup", "description": "Help with first-time configuration.", "sort_order": 10},
            {"name": "User Training", "description": "Training or walkthrough request.", "sort_order": 20},
            {"name": "Data Migration", "description": "Moving data from another system.", "sort_order": 30},
        ],
    },
    {
        "name": "Other",
        "description": "Anything that doesn't fit the above.",
        "sort_order": 99,
        "children": [
            {"name": "Feature Request", "description": "Request for a new feature or enhancement.", "sort_order": 10},
            {"name": "Documentation", "description": "Missing or unclear documentation.", "sort_order": 20},
        ],
    },
]

TAGS: list[dict[str, Any]] = [
    {"name": "bug",             "color": "#ef4444", "sort_order": 10},
    {"name": "feature-request", "color": "#8b5cf6", "sort_order": 20},
    {"name": "urgent",          "color": "#f97316", "sort_order": 30},
    {"name": "billing",         "color": "#14b8a6", "sort_order": 40},
    {"name": "account",         "color": "#3b82f6", "sort_order": 50},
    {"name": "integration",     "color": "#6366f1", "sort_order": 60},
    {"name": "performance",     "color": "#f59e0b", "sort_order": 70},
    {"name": "security",        "color": "#dc2626", "sort_order": 80},
    {"name": "documentation",   "color": "#64748b", "sort_order": 90},
    {"name": "feedback",        "color": "#84cc16", "sort_order": 100},
]

AUTOMATIONS: list[dict[str, Any]] = []  # Legacy — kept for backward-compat; no longer seeded.


# ---------------------------------------------------------------------------
# Seed loader — reads .seed/processes.json
# ---------------------------------------------------------------------------

_SEED_DIR = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), ".seed")


def _load_seed_processes() -> list[dict[str, Any]]:
    """Load process definitions from .seed/processes.json."""
    seed_file = os.path.join(_SEED_DIR, "processes.json")
    if not os.path.exists(seed_file):
        _log.warning("seed_processes: .seed/processes.json not found at %s", seed_file)
        return []
    with open(seed_file, encoding="utf-8") as fh:
        return json.load(fh)


# ---------------------------------------------------------------------------
# Public helper — callable from signals / tests without a Command instance
# ---------------------------------------------------------------------------

@transaction.atomic
def seed_tenant_defaults(tenant) -> None:  # noqa: ANN001
    """Idempotent seed of helpdesk defaults for a single tenant.

    Called automatically via ``post_save`` signal on ``Tenant`` creation and
    can be invoked directly in tests or migration scripts.
    """
    from simorgh.apps.helpdesk.models import Category, Queue, SLAPolicy, Tag
    from simorgh.apps.organizations.models import OrganizationNode
    from simorgh.apps.workflow.models import ProcessDefinition

    org_node = (
        OrganizationNode.objects
        .filter(tenant=tenant, parent__isnull=True)
        .order_by("id")
        .first()
    )
    if org_node is None:
        _log.warning("seed_tenant_defaults: no root org node for tenant %s — skipping", tenant.pk)
        return

    # Default Queue
    Queue.objects.get_or_create(
        tenant=tenant,
        is_default=True,
        defaults={"organization_node_id": org_node.pk, **DEFAULT_QUEUE},
    )

    # SLA Policies
    for sla_def in SLA_POLICIES:
        SLAPolicy.objects.update_or_create(
            tenant=tenant,
            name=sla_def["name"],
            defaults={"organization_node_id": org_node.pk, **sla_def},
        )

    # Categories + subcategories (two-level)
    for cat_def in CATEGORIES:
        parent, _ = Category.objects.update_or_create(
            tenant=tenant,
            name=cat_def["name"],
            parent__isnull=True,
            defaults={
                "organization_node_id": org_node.pk,
                "description": cat_def["description"],
                "sort_order": cat_def["sort_order"],
                "is_active": True,
            },
        )
        for child_def in cat_def.get("children", []):
            Category.objects.update_or_create(
                tenant=tenant,
                name=child_def["name"],
                parent=parent,
                defaults={
                    "organization_node_id": org_node.pk,
                    "description": child_def.get("description", ""),
                    "sort_order": child_def["sort_order"],
                    "is_active": True,
                },
            )

    # Tags
    for tag_def in TAGS:
        Tag.objects.update_or_create(
            tenant=tenant,
            name=tag_def["name"],
            defaults={
                "organization_node_id": org_node.pk,
                "color": tag_def["color"],
                "sort_order": tag_def["sort_order"],
                "is_active": True,
            },
        )

    # Process Definitions — loaded from .seed/processes.json, registered in workflow engine
    for proc_def in _load_seed_processes():
        seed_key = proc_def.get("seed_key", "")
        if not seed_key:
            continue
        ProcessDefinition.objects.update_or_create(
            tenant=tenant,
            seed_key=seed_key,
            defaults={
                "organization_node_id": org_node.pk,
                "name": proc_def["name"],
                "description": proc_def.get("description", ""),
                "trigger_event": proc_def["trigger_event"],
                "conditions": proc_def.get("conditions", []),
                "actions": proc_def.get("actions", []),
                "is_active": proc_def.get("is_active", True),
                "sort_order": proc_def.get("sort_order", 0),
            },
        )


# ---------------------------------------------------------------------------
# Command
# ---------------------------------------------------------------------------

class Command(BaseCommand):
    help = "Seed helpdesk module with default queues, SLA policies, categories, tags, and automations."

    def add_arguments(self, parser):
        parser.add_argument(
            "--tenant",
            default=None,
            help="Slug or PK of a specific tenant to seed (default: all active tenants).",
        )
        parser.add_argument(
            "--demo",
            action="store_true",
            default=False,
            help="Also create demo tickets for testing (only safe on dev/staging).",
        )

    def handle(self, *args, **options):
        from simorgh.apps.tenants.models import Tenant

        tenant_filter = options.get("tenant")
        seed_demo = options.get("demo", False)

        if tenant_filter:
            qs = Tenant.objects.filter(is_active=True)
            # Support slug or pk lookup
            try:
                pk = int(tenant_filter)
                qs = qs.filter(pk=pk)
            except ValueError:
                qs = qs.filter(slug=tenant_filter)
            if not qs.exists():
                raise CommandError(f"Tenant {tenant_filter!r} not found or not active.")
            tenants = list(qs)
        else:
            tenants = list(Tenant.objects.filter(is_active=True))

        if not tenants:
            self.stderr.write(self.style.WARNING("No active tenants found — nothing seeded."))
            return

        self.stdout.write(self.style.MIGRATE_HEADING(
            f"Seeding helpdesk for {len(tenants)} tenant(s)…"
        ))

        total_created = {"queues": 0, "sla": 0, "categories": 0, "tags": 0, "processes": 0}
        for tenant in tenants:
            created = self._seed_tenant(tenant)
            for k, v in created.items():
                total_created[k] += v

        if seed_demo:
            self._seed_demo(tenants[0])

        self.stdout.write(self.style.SUCCESS(
            f"\n✓ Seeding complete: "
            f"queues={total_created['queues']}  "
            f"sla_policies={total_created['sla']}  "
            f"categories={total_created['categories']}  "
            f"tags={total_created['tags']}  "
            f"processes={total_created['processes']}"
        ))
        self._print_role_reminder()

    # ------------------------------------------------------------------
    # Per-tenant seed
    # ------------------------------------------------------------------

    @transaction.atomic
    def _seed_tenant(self, tenant) -> dict[str, int]:
        from simorgh.apps.helpdesk.models import Category, Queue, SLAPolicy, Tag
        from simorgh.apps.organizations.models import OrganizationNode
        from simorgh.apps.workflow.models import ProcessDefinition

        # Resolve the root org node for this tenant.
        org_node = (
            OrganizationNode.objects
            .filter(tenant=tenant, parent__isnull=True)
            .order_by("id")
            .first()
        )
        if org_node is None:
            self.stderr.write(
                self.style.WARNING(
                    f"  [{tenant.slug}] No root org node — skipping (run seed_organizations first)."
                )
            )
            return {"queues": 0, "sla": 0, "categories": 0, "tags": 0, "processes": 0}

        counts: dict[str, int] = {"queues": 0, "sla": 0, "categories": 0, "tags": 0, "processes": 0}

        # 1. Default Queue
        queue, created = Queue.objects.get_or_create(
            tenant=tenant,
            is_default=True,
            defaults={
                "organization_node_id": org_node.pk,
                **DEFAULT_QUEUE,
            },
        )
        if created:
            counts["queues"] += 1
            self.stdout.write(f"  [{tenant.slug}] ✓ Created default queue: {queue.name}")
        else:
            self.stdout.write(f"  [{tenant.slug}] — Queue already exists: {queue.name}")

        # 2. SLA Policies
        for sla_def in SLA_POLICIES:
            _, created = SLAPolicy.objects.update_or_create(
                tenant=tenant,
                name=sla_def["name"],
                defaults={
                    "organization_node_id": org_node.pk,
                    **sla_def,
                },
            )
            if created:
                counts["sla"] += 1

        self.stdout.write(
            f"  [{tenant.slug}] ✓ SLA policies: {counts['sla']} created, "
            f"{len(SLA_POLICIES) - counts['sla']} already existed"
        )

        # 3. Categories (two-level hierarchy)
        total_cats = 0
        for cat_def in CATEGORIES:
            parent, created = Category.objects.update_or_create(
                tenant=tenant,
                name=cat_def["name"],
                parent__isnull=True,
                defaults={
                    "organization_node_id": org_node.pk,
                    "description": cat_def["description"],
                    "sort_order": cat_def["sort_order"],
                    "is_active": True,
                },
            )
            if created:
                total_cats += 1
            for child_def in cat_def.get("children", []):
                _, child_created = Category.objects.update_or_create(
                    tenant=tenant,
                    name=child_def["name"],
                    parent=parent,
                    defaults={
                        "organization_node_id": org_node.pk,
                        "description": child_def.get("description", ""),
                        "sort_order": child_def["sort_order"],
                        "is_active": True,
                    },
                )
                if child_created:
                    total_cats += 1
        counts["categories"] = total_cats

        self.stdout.write(
            f"  [{tenant.slug}] ✓ Categories: {counts['categories']} created"
        )

        # 4. Tags
        for tag_def in TAGS:
            _, created = Tag.objects.update_or_create(
                tenant=tenant,
                name=tag_def["name"],
                defaults={
                    "organization_node_id": org_node.pk,
                    "color": tag_def["color"],
                    "sort_order": tag_def["sort_order"],
                    "is_active": True,
                },
            )
            if created:
                counts["tags"] += 1

        self.stdout.write(
            f"  [{tenant.slug}] ✓ Tags: {counts['tags']} created, "
            f"{len(TAGS) - counts['tags']} already existed"
        )

        # 5. Process Definitions (workflow engine automation rules)
        seed_processes = _load_seed_processes()
        for proc_def in seed_processes:
            seed_key = proc_def.get("seed_key", "")
            if not seed_key:
                continue
            _, created = ProcessDefinition.objects.update_or_create(
                tenant=tenant,
                seed_key=seed_key,
                defaults={
                    "organization_node_id": org_node.pk,
                    "name": proc_def["name"],
                    "description": proc_def.get("description", ""),
                    "trigger_event": proc_def["trigger_event"],
                    "conditions": proc_def.get("conditions", []),
                    "actions": proc_def.get("actions", []),
                    "is_active": proc_def.get("is_active", True),
                    "sort_order": proc_def.get("sort_order", 0),
                },
            )
            if created:
                counts["processes"] += 1

        self.stdout.write(
            f"  [{tenant.slug}] ✓ Processes: {counts['processes']} created, "
            f"{len(seed_processes) - counts['processes']} already existed"
        )

        return counts

    # ------------------------------------------------------------------
    # Demo data (dev/staging only)
    # ------------------------------------------------------------------

    def _seed_demo(self, tenant) -> None:
        """Create a handful of demo tickets for UI testing."""
        from django.contrib.auth import get_user_model
        from simorgh.apps.helpdesk.models import Queue
        from simorgh.apps.helpdesk.services import TicketService
        from simorgh.apps.organizations.models import OrganizationNode

        User = get_user_model()
        self.stdout.write(self.style.MIGRATE_HEADING("\nSeeding demo tickets…"))

        queue = Queue.objects.filter(tenant=tenant, is_default=True).first()
        if not queue:
            self.stderr.write("  No default queue found — skipping demo tickets.")
            return

        org_node = (
            OrganizationNode.objects
            .filter(tenant=tenant, parent__isnull=True)
            .first()
        )
        if not org_node:
            return

        demo_tickets = [
            {
                "subject": "Cannot log in to my account",
                "description": "I keep getting 'invalid password' even after resetting.",
                "priority": "high",
                "requester_email": "alice@example.com",
                "requester_name": "Alice Demo",
            },
            {
                "subject": "Invoice #1042 is incorrect",
                "description": "The invoice amount does not match our contract terms.",
                "priority": "normal",
                "requester_email": "bob@example.com",
                "requester_name": "Bob Demo",
            },
            {
                "subject": "Feature request: bulk export to CSV",
                "description": "We need the ability to export all records to CSV for reporting.",
                "priority": "low",
                "requester_email": "carol@example.com",
                "requester_name": "Carol Demo",
            },
            {
                "subject": "API returns 500 on POST /orders",
                "description": "Since yesterday, our integration keeps receiving 500 errors.",
                "priority": "urgent",
                "requester_email": "dev@example.com",
                "requester_name": "DevOps Demo",
            },
            {
                "subject": "How do I set up SSO with Okta?",
                "description": "We want to configure SAML 2.0 SSO via Okta.",
                "priority": "normal",
                "requester_email": "it@example.com",
                "requester_name": "IT Admin Demo",
            },
        ]

        created = 0
        for ticket_data in demo_tickets:
            # Skip if demo ticket already exists (idempotent by subject)
            from simorgh.apps.helpdesk.models import Ticket
            if Ticket.objects.filter(
                tenant=tenant,
                subject=ticket_data["subject"],
                requester_email=ticket_data["requester_email"],
            ).exists():
                continue

            TicketService.create(
                tenant_id=tenant.pk,
                organization_node_id=org_node.pk,
                queue_id=queue.pk,
                **ticket_data,
            )
            created += 1

        self.stdout.write(self.style.SUCCESS(f"  Created {created} demo tickets."))

    # ------------------------------------------------------------------
    # Role reminder
    # ------------------------------------------------------------------

    def _print_role_reminder(self) -> None:
        from simorgh.apps.helpdesk.permissions import ROLE_AGENT, ROLE_PORTAL_USER, ROLE_SUPERVISOR

        self.stdout.write("\n" + self.style.MIGRATE_HEADING("IAM Role Definitions (manual step):"))
        self.stdout.write(
            "  The following roles should be created in the IAM module\n"
            "  (Admin → IAM → Roles) or via the platform seed command:\n"
        )
        for role in (ROLE_AGENT, ROLE_SUPERVISOR, ROLE_PORTAL_USER):
            perms = ", ".join(role["permissions"])
            self.stdout.write(
                f"  • [{role['code']}] {role['name']}\n"
                f"    Permissions: {perms}\n"
            )
