"""`python manage.py seed_dev` — idempotent dev seed.

Currently seeds the demo tenant "گروه صنعتی مومنین", its owner / member users,
a root organization node, and the subsidiary workspace "شرکت سولان".

Re-running the command is safe: every step uses ``get_or_create`` / lookups,
so existing rows are reused. Passwords are reset on every run to keep the
documented credentials valid even if a developer changed them locally.
"""

from __future__ import annotations

from typing import Any

from django.contrib.auth import get_user_model
from django.core.management.base import BaseCommand
from django.db import transaction

from simorgh.apps.iam.models import Role
from simorgh.apps.memberships.models import Membership, MembershipStatus
from simorgh.apps.organizations.models import OrganizationNode, OrganizationNodeType
from simorgh.apps.organizations.services import create_node
from simorgh.apps.tenants.models import Tenant, TenantStatus
from simorgh.apps.workspaces.models import Workspace, WorkspaceKind
from simorgh.apps.workspaces.services import add_member, create_workspace


# ---------------------------------------------------------------------------
# Demo data (keep in sync with docs/onboarding notes)
# ---------------------------------------------------------------------------
TENANT_SLUG = "momenin"
TENANT_NAME = "گروه صنعتی مومنین"

ROOT_ORG_NAME = "گروه صنعتی مومنین"
SUBSIDIARY_ORG_NAME = "شرکت سولان"

WORKSPACE_SLUG = "solan"
WORKSPACE_NAME = "شرکت سولان"

# Users — identifier is phone, login works with phone OR email.
USERS: list[dict[str, Any]] = [
    {
        "first_name": "جواد",
        "last_name": "کاشانی",
        "phone": "09127972696",
        "password": "K@shani2696",
        "is_owner": True,
    },
    {
        "first_name": "رامین",
        "last_name": "درخشی",
        "phone": "09120686818",
        "password": "R@min6818",
        "is_owner": False,
    },
]


class Command(BaseCommand):
    help = "Seed the development database with the demo tenant + users (idempotent)."

    @transaction.atomic
    def handle(self, *args: object, **options: object) -> None:
        tenant = self._seed_tenant()
        root_node = self._seed_root_node(tenant)
        users = self._seed_users(tenant)
        subsidiary = self._seed_subsidiary_node(tenant, root_node)
        workspace = self._seed_workspace(tenant, subsidiary)
        self._seed_memberships(workspace, users)
        self._seed_iam_memberships(tenant, root_node, users)
        self._seed_superuser_memberships(tenant, root_node)
        self._run_platform_seeds()
        self._summary(tenant, workspace, users)

    # ------------------------------------------------------------------ tenant
    def _seed_tenant(self) -> Tenant:
        tenant, created = Tenant.objects.get_or_create(
            slug=TENANT_SLUG,
            defaults={
                "name": TENANT_NAME,
                "status": TenantStatus.ACTIVE,
            },
        )
        if not created and tenant.name != TENANT_NAME:
            tenant.name = TENANT_NAME
            tenant.save(update_fields=("name",))
        self._line(f"tenant {tenant.slug!r}", created)
        return tenant

    # -------------------------------------------------------------- org nodes
    def _seed_root_node(self, tenant: Tenant) -> OrganizationNode:
        node = (
            OrganizationNode.objects.filter(tenant=tenant, parent__isnull=True)
            .order_by("depth", "pk")
            .first()
        )
        if node is not None:
            self._line(f"root org node {node.name!r}", False)
            return node
        node = create_node(
            tenant_id=tenant.pk,
            name=ROOT_ORG_NAME,
            type=OrganizationNodeType.ORGANIZATION,
        )
        self._line(f"root org node {node.name!r}", True)
        return node

    def _seed_subsidiary_node(
        self, tenant: Tenant, parent: OrganizationNode
    ) -> OrganizationNode:
        node = OrganizationNode.objects.filter(
            tenant=tenant, parent=parent, name=SUBSIDIARY_ORG_NAME
        ).first()
        if node is not None:
            self._line(f"subsidiary org node {node.name!r}", False)
            return node
        node = create_node(
            tenant_id=tenant.pk,
            name=SUBSIDIARY_ORG_NAME,
            type=OrganizationNodeType.COMPANY,
            parent=parent,
        )
        self._line(f"subsidiary org node {node.name!r}", True)
        return node

    # ---------------------------------------------------------------- users
    def _seed_users(self, tenant: Tenant) -> list[Any]:
        User = get_user_model()
        results: list[Any] = []
        for spec in USERS:
            phone = spec["phone"]
            email = f"{phone}@simorgh.local"
            display_name = f"{spec['first_name']} {spec['last_name']}".strip()
            user, created = User.objects.get_or_create(
                email=email,
                defaults={
                    "mobile": phone,
                    "username": phone,
                    "first_name": spec["first_name"],
                    "last_name": spec["last_name"],
                    "is_active": True,
                    "is_staff": spec["is_owner"],
                    "is_superuser": False,
                    "language": None,
                    "timezone": None,
                },
            )
            # Keep identity fields in sync on re-runs.
            dirty = False
            for field, value in (
                ("username", phone),
                ("first_name", spec["first_name"]),
                ("last_name", spec["last_name"]),
                ("is_staff", spec["is_owner"]),
            ):
                if getattr(user, field) != value:
                    setattr(user, field, value)
                    dirty = True
            if dirty:
                user.save()
            # Always reset password so documented creds keep working.
            user.set_password(spec["password"])
            user.save(update_fields=("password",))
            self._line(f"user {display_name} ({phone})", created)
            results.append(user)

        # Owner gets tenant-admin signalling via is_staff above. Membership
        # role assignment is left to the IAM seeding step (out of scope here).
        _ = tenant  # acknowledged; per-tenant role wiring will land later
        return results

    # ----------------------------------------------------------- workspace
    def _seed_workspace(
        self, tenant: Tenant, anchor: OrganizationNode
    ) -> Workspace:
        ws = Workspace.objects.filter(tenant=tenant, slug=WORKSPACE_SLUG).first()
        if ws is not None:
            if ws.name != WORKSPACE_NAME:
                ws.name = WORKSPACE_NAME
                ws.save(update_fields=("name",))
            self._line(f"workspace {ws.slug!r}", False)
            return ws
        ws = create_workspace(
            tenant,
            slug=WORKSPACE_SLUG,
            name=WORKSPACE_NAME,
            kind=WorkspaceKind.INTERNAL,
        )
        self._line(f"workspace {ws.slug!r}", True)
        return ws

    # --------------------------------------------------------- memberships
    def _seed_memberships(self, workspace: Workspace, users: list[Any]) -> None:
        for user in users:
            membership = add_member(workspace, user)
            self._line(
                f"membership {user.email} → {workspace.slug}",
                membership.pk is not None,
            )

    # ----------------------------------------------------- IAM memberships
    def _seed_iam_memberships(
        self, tenant: Tenant, root_node: OrganizationNode, users: list[Any]
    ) -> None:
        """Create a tenant-scoped role + IAM memberships so the tenant
        resolver's membership-fallback can find a tenant for these users."""
        role, created = Role.objects.get_or_create(
            tenant=tenant,
            code="tenant_member",
            defaults={
                "name": "Tenant Member",
                "description": "Default seeded role granting tenant access.",
                "is_system": False,
            },
        )
        self._line(f"role {role.code!r}", created)
        # Membership is a (tenant, org_node, role) slot; users are M2M.
        membership, created = Membership.objects.get_or_create(
            tenant=tenant,
            organization_node=root_node,
            role=role,
            defaults={"status": MembershipStatus.ACTIVE},
        )
        for user in users:
            if not membership.users.filter(pk=user.pk).exists():
                membership.users.add(user)
                self._line(f"iam membership {user.email} → {tenant.slug}", True)
            else:
                self._line(f"iam membership {user.email} → {tenant.slug}", False)

    # ------------------------------------------------- superuser memberships
    def _seed_superuser_memberships(
        self, tenant: Tenant, root_node: OrganizationNode
    ) -> None:
        """Ensure every existing superuser has an active membership so
        the tenant resolver can find a tenant for admin accounts."""
        User = get_user_model()
        role = Role.objects.get(tenant=tenant, code="tenant_member")
        # Re-use (or create) the shared membership slot for this role.
        membership, _ = Membership.objects.get_or_create(
            tenant=tenant,
            organization_node=root_node,
            role=role,
            defaults={"status": MembershipStatus.ACTIVE},
        )
        if membership.status != MembershipStatus.ACTIVE:
            membership.status = MembershipStatus.ACTIVE
            membership.save(update_fields=("status",))
        for user in User.objects.filter(is_superuser=True):
            already = membership.users.filter(pk=user.pk).exists()
            if not already:
                membership.users.add(user)
            self._line(f"superuser membership {user.email} → {tenant.slug}", not already)

    # --------------------------------------------------- platform seeds
    def _run_platform_seeds(self) -> None:
        """Delegate to run_seeds management command for .seeds/*.py files."""
        from django.core.management import call_command
        self.stdout.write("\nRunning platform seeds (.seeds/)...")
        call_command("run_seeds", stdout=self.stdout, stderr=self.stderr)

    # ------------------------------------------------------------- output
    def _line(self, label: str, created: bool) -> None:
        marker = self.style.SUCCESS("created") if created else self.style.NOTICE("exists ")
        self.stdout.write(f"  [{marker}] {label}")

    def _summary(
        self, tenant: Tenant, workspace: Workspace, users: list[Any]
    ) -> None:
        self.stdout.write("")
        self.stdout.write(self.style.SUCCESS("Seed complete."))
        self.stdout.write(f"  Tenant      : {tenant.name} (slug={tenant.slug})")
        self.stdout.write(f"  Workspace   : {workspace.name} (slug={workspace.slug})")
        self.stdout.write("  Login (phone OR email + password):")
        for user, spec in zip(users, USERS, strict=True):
            self.stdout.write(
                f"    - {user.first_name} {user.last_name}: "
                f"{spec['phone']}  /  {user.email}  /  pwd={spec['password']}"
            )
        self.stdout.write("")
        self.stdout.write(
            self.style.WARNING(
                "Note: chat fixtures are not seeded — the chat module has no "
                "backend yet (frontend popover is a placeholder)."
            )
        )
