"""
Audit Firm ERP -- UAT seed data for Playwright v2.4.1 IMAP.

Purpose:
  - Replace old @tenant-a.test / @tenant-b.test UAT users with real @vavalam.com test emails.
  - Create all Playwright role users.
  - Create tenants, branches, clients, employees/staff, service catalogue, task templates,
    subscriptions/engagements, task instances, notice case, and a local storage node.

Run inside ERP container from project root after migrations:
    cd /app
    PYTHONPATH=/app UAT_SEED_PASSWORD='Password@123' python scripts/seed_uat_data.py

Safe/idempotent for UAT: re-running updates/reuses existing UAT records.
Do NOT run against live production data.
"""
from __future__ import annotations

import hashlib
import os
import sys
from datetime import date, datetime, timedelta, timezone

PASSWORD = os.getenv("UAT_SEED_PASSWORD", "Password@123")
ACTIVE_FY = os.getenv("ACTIVE_FY", "2025-26")
PREVIOUS_FY = os.getenv("PREVIOUS_FY", "2024-25")
ASSESSMENT_YEAR = os.getenv("ASSESSMENT_YEAR", "2026-27")
LSA_SECRET = os.getenv("UAT_LSA_SECRET", "uat-local-storage-agent-secret")

ROLE_NAME = {
    "system_admin": "System Admin",
    "firm_admin": "Firm Admin",
    "partner": "Partner",
    "manager": "Branch Manager",
    "staff": "Staff",
    "client": "Client",
    "consultant": "Consultant",
}

LEGACY_EMAIL_MAP = {
    "uat.firmadmin@tenant-a.test": "uat.firmadmin@vavalam.com",
    "uat.partner@tenant-a.test": "uat.partner@vavalam.com",
    "uat.manager@tenant-a.test": "uat.manager@vavalam.com",
    "uat.staff@tenant-a.test": "uat.staff@vavalam.com",
    "uat.client@tenant-a.test": "uat.client@vavalam.com",
    "uat.consultant@tenant-a.test": "uat.consultant@vavalam.com",
    "uat.firmadmin@tenant-b.test": "uat.firmadminb@vavalam.com",
}


def fail(msg: str) -> None:
    print(f"\n[seed] ERROR: {msg}", file=sys.stderr)
    sys.exit(1)


def main() -> None:
    try:
        from app.core.db.common import CommonSessionLocal
        from app.core.security.passwords import hash_password
        from app.modules.core.iam.models import User
        from app.modules.core.tenancy.models import Tenant, Branch, FinancialYear
        from app.modules.core.rbac.models import Role, UserRole
        from app.modules.clients.models import Client
        from app.modules.employees.models import Employee
        from app.modules.services.models import (
            ServiceCategory,
            ServiceCatalogue,
            ServiceDefaultTaskTemplate,
            FirmServiceSelection,
            FirmServiceTaskTemplate,
            FirmTaskDocumentRequirement,
            ServiceDueDateRule,
            ClientServiceSubscription,
            ClientServiceTaskInstance,
        )
        from app.modules.documents.models import (
            BranchStorageNode,
            EngagementDocument,
            EngagementDocumentVersion,
            DocumentStorageJob,
        )
    except Exception as exc:
        fail(
            "Could not import ERP modules. Run this from ERP project root inside the app container. "
            f"Underlying import error: {exc!r}"
        )

    try:
        from app.modules.notice_cases.models import NoticeCase
    except Exception:
        NoticeCase = None

    db = CommonSessionLocal()
    ids: dict[str, object] = {}

    def valid_data(Model, data: dict) -> dict:
        valid = {c.name for c in Model.__table__.columns}
        return {k: v for k, v in data.items() if k in valid}

    def get_or_create(Model, lookup: dict, defaults: dict | None = None):
        obj = db.query(Model).filter_by(**lookup).first()
        if obj:
            if defaults:
                for k, v in valid_data(Model, defaults).items():
                    setattr(obj, k, v)
            db.flush()
            return obj, False
        data = {**lookup, **(defaults or {})}
        obj = Model(**valid_data(Model, data))
        db.add(obj)
        db.flush()
        return obj, True

    def role_by_name(name: str):
        return db.query(Role).filter(Role.name == name).first()

    def assign_role(user, role_label: str) -> None:
        role_name = ROLE_NAME[role_label]
        role = role_by_name(role_name)
        if not role:
            print(f"[seed] WARNING: role '{role_name}' not found. Run/restart ERP startup seed first.")
            return
        exists = db.query(UserRole).filter_by(user_id=user.id, role_id=role.id).first()
        if not exists:
            db.add(UserRole(user_id=user.id, role_id=role.id))
            db.flush()

    def deactivate_user(email: str) -> None:
        user = db.query(User).filter(User.email == email).first()
        if user:
            user.allow_login = False
            user.is_active = False
            if hasattr(user, "deleted_at"):
                user.deleted_at = datetime.now(timezone.utc)
            db.flush()

    def ensure_user(email: str, full_name: str, role_labels: list[str], tenant, branch, *, locked=False, allow_login=True):
        # If old fake email exists and mapped to this real email, update old record in-place unless real already exists.
        for old_email, new_email in LEGACY_EMAIL_MAP.items():
            if new_email == email:
                old_user = db.query(User).filter(User.email == old_email).first()
                real_user = db.query(User).filter(User.email == email).first()
                if old_user and not real_user:
                    old_user.email = email
                    old_user.full_name = full_name
                    old_user.tenant_id = tenant.id
                    old_user.branch_id = branch.id
                    old_user.password_hash = hash_password(PASSWORD)
                    old_user.is_active = True
                    old_user.allow_login = allow_login
                    old_user.is_locked = locked
                    old_user.must_change_password = False
                    db.flush()
                    for role_label in role_labels:
                        assign_role(old_user, role_label)
                    return old_user
                if old_user and real_user and old_user.id != real_user.id:
                    deactivate_user(old_email)

        user, _ = get_or_create(
            User,
            {"email": email},
            {
                "full_name": full_name,
                "password_hash": hash_password(PASSWORD),
                "tenant_id": tenant.id,
                "branch_id": branch.id,
                "is_active": True,
                "allow_login": allow_login,
                "is_locked": locked,
                "must_change_password": False,
                "mobile": "9000000000",
            },
        )
        user.password_hash = hash_password(PASSWORD)
        user.full_name = full_name
        user.tenant_id = tenant.id
        user.branch_id = branch.id
        user.is_active = True
        user.allow_login = allow_login
        user.is_locked = locked
        user.must_change_password = False
        for role_label in role_labels:
            assign_role(user, role_label)
        db.flush()
        return user

    def ensure_employee(code: str, user, tenant, branch, designation: str, department="Audit"):
        emp, _ = get_or_create(
            Employee,
            {"tenant_id": tenant.id, "employee_code": code},
            {
                "branch_id": branch.id,
                "user_id": user.id,
                "full_name": user.full_name,
                "email": user.email,
                "mobile": getattr(user, "mobile", None) or "9000000000",
                "date_of_joining": date(2025, 4, 1),
                "employment_type": "full_time",
                "status": "active",
                "is_active": True,
                "department": department,
                "designation": designation,
                "pan": f"UAT{code[-3:].zfill(3)}P",
            },
        )
        return emp

    def ensure_fy(tenant, year_code: str, ay: str, start: date, end: date, current: bool):
        fy, _ = get_or_create(
            FinancialYear,
            {"tenant_id": tenant.id, "year_code": year_code},
            {
                "assessment_year": ay,
                "start_date": start,
                "end_date": end,
                "is_current": current,
                "is_locked": False,
            },
        )
        return fy

    def ensure_service_category(code: str, name: str, sort_order: int):
        return get_or_create(
            ServiceCategory,
            {"code": code},
            {"name": name, "sort_order": sort_order, "is_active": True},
        )[0]

    def ensure_catalogue(code: str, name: str, category_obj, recurrence: str, engagement_type="non_assurance", sort_order=100):
        svc, _ = get_or_create(
            ServiceCatalogue,
            {"service_code": code},
            {
                "service_name": name,
                "category": category_obj.name,
                "category_id": category_obj.id,
                "recurrence_type": recurrence,
                "engagement_type": engagement_type,
                "sort_order": sort_order,
                "description": f"UAT seed service: {name}",
                "applicable_individual": True,
                "applicable_proprietorship": True,
                "applicable_partnership": True,
                "applicable_llp": True,
                "applicable_company": True,
                "is_active": True,
                "is_client_requestable": True,
                "is_consultant_requestable": False,
            },
        )
        return svc

    def ensure_default_task(svc, seq: int, name: str, role: str, review=False):
        return get_or_create(
            ServiceDefaultTaskTemplate,
            {"service_catalogue_id": svc.id, "sequence_no": seq},
            {
                "task_name": name,
                "description": f"UAT default task: {name}",
                "default_role_name": role,
                "is_mandatory": True,
                "requires_review": review,
                "is_active": True,
            },
        )[0]

    def enable_firm_service(tenant, branch, svc, user):
        return get_or_create(
            FirmServiceSelection,
            {"tenant_id": tenant.id, "service_catalogue_id": svc.id},
            {
                "is_enabled": True,
                "default_branch_id": branch.id,
                "activated_by_user_id": user.id,
                "updated_by_user_id": user.id,
            },
        )[0]

    def ensure_firm_task(tenant, svc, seq: int, name: str, role: str, user, review=False):
        task, _ = get_or_create(
            FirmServiceTaskTemplate,
            {"tenant_id": tenant.id, "service_catalogue_id": svc.id, "sequence_no": seq},
            {
                "task_name": name,
                "description": f"UAT firm task: {name}",
                "default_role_name": role,
                "is_mandatory": True,
                "requires_review": review,
                "is_active": True,
                "created_by_user_id": user.id,
                "updated_by_user_id": user.id,
            },
        )
        return task

    def ensure_doc_requirement(tenant, svc, task, name: str, dtype="GENERAL"):
        return get_or_create(
            FirmTaskDocumentRequirement,
            {"tenant_id": tenant.id, "firm_task_template_id": task.id, "document_name": name},
            {
                "service_catalogue_id": svc.id,
                "document_type": dtype,
                "is_mandatory": True,
                "allowed_file_types": "pdf,xlsx,docx,jpg,png,txt",
                "instructions": "UAT seeded document requirement",
                "sort_order": task.sequence_no,
                "is_active": True,
            },
        )[0]

    def ensure_due_rule(svc, name: str, period_type: str, day: int | None, month: int | None, offset=0):
        return get_or_create(
            ServiceDueDateRule,
            {"service_catalogue_id": svc.id, "rule_name": name},
            {
                "period_type": period_type,
                "due_year_basis": "financial_year_start",
                "due_day": day,
                "due_month": month,
                "due_month_offset": offset,
                "sort_order": 100,
                "is_active": True,
                "remarks": "UAT seed due date rule",
            },
        )[0]

    def ensure_subscription(tenant, branch, client, svc, firm_selection, partner, manager, staff, due_rule=None):
        sub, _ = get_or_create(
            ClientServiceSubscription,
            {"tenant_id": tenant.id, "client_id": client.id, "service_catalogue_id": svc.id, "financial_year": ACTIVE_FY},
            {
                "branch_id": branch.id,
                "firm_service_selection_id": firm_selection.id,
                "assigned_partner_user_id": partner.id,
                "assigned_manager_user_id": manager.id,
                "assigned_staff_user_id": staff.id,
                "review_partner_user_id": partner.id,
                "assessment_year": ASSESSMENT_YEAR,
                "engagement_type": svc.engagement_type,
                "due_date_rule_id": due_rule.id if due_rule else None,
                "original_due_date": date.today() + timedelta(days=30),
                "current_due_date": date.today() + timedelta(days=30),
                "due_date_source": "seed",
                "start_date": date.today(),
                "end_date": date.today() + timedelta(days=365),
                "status": "active",
                "remarks": "UAT seeded engagement/subscription",
                "is_active": True,
                "is_locked": False,
                "created_by_user_id": partner.id,
                "updated_by_user_id": partner.id,
            },
        )
        return sub

    def ensure_task_instance(tenant, branch, client, sub, svc, firm_task, assigned_user, days=7):
        task, _ = get_or_create(
            ClientServiceTaskInstance,
            {"subscription_id": sub.id, "firm_task_template_id": firm_task.id, "financial_year": ACTIVE_FY},
            {
                "tenant_id": tenant.id,
                "branch_id": branch.id,
                "client_id": client.id,
                "service_catalogue_id": svc.id,
                "assessment_year": ASSESSMENT_YEAR,
                "task_name": firm_task.task_name,
                "description": firm_task.description,
                "sequence_no": firm_task.sequence_no,
                "default_role_name": firm_task.default_role_name,
                "assigned_to_user_id": assigned_user.id,
                "internal_target_date": date.today() + timedelta(days=days),
                "status": "pending",
                "priority": "normal",
                "is_active": True,
                "is_locked": False,
                "created_by_user_id": assigned_user.id,
                "updated_by_user_id": assigned_user.id,
            },
        )
        return task

    try:
        # Tenants and branches
        tenant_a, _ = get_or_create(Tenant, {"code": "UAT-A"}, {"name": "UAT Tenant A", "is_active": True, "firm_type": "partnership", "contact_email": "support@vavalam.com"})
        tenant_b, _ = get_or_create(Tenant, {"code": "UAT-B"}, {"name": "UAT Tenant B", "is_active": True, "firm_type": "partnership", "contact_email": "support@vavalam.com"})
        branch_a, _ = get_or_create(Branch, {"tenant_id": tenant_a.id, "code": "UAT-BA"}, {"name": "UAT Branch A", "is_active": True, "is_head_office": True, "timezone": "Asia/Kolkata", "local_storage_path": "D:/UAT/BranchA"})
        branch_b, _ = get_or_create(Branch, {"tenant_id": tenant_b.id, "code": "UAT-BB"}, {"name": "UAT Branch B", "is_active": True, "is_head_office": True, "timezone": "Asia/Kolkata", "local_storage_path": "D:/UAT/BranchB"})

        ids["TENANT_A_ID"] = tenant_a.id
        ids["TENANT_B_ID"] = tenant_b.id
        ids["BRANCH_A_ID"] = branch_a.id
        ids["BRANCH_B_ID"] = branch_b.id

        fy_a = ensure_fy(tenant_a, ACTIVE_FY, ASSESSMENT_YEAR, date(2025, 4, 1), date(2026, 3, 31), True)
        ensure_fy(tenant_a, PREVIOUS_FY, "2025-26", date(2024, 4, 1), date(2025, 3, 31), False)
        fy_b = ensure_fy(tenant_b, ACTIVE_FY, ASSESSMENT_YEAR, date(2025, 4, 1), date(2026, 3, 31), True)
        ensure_fy(tenant_b, PREVIOUS_FY, "2025-26", date(2024, 4, 1), date(2025, 3, 31), False)
        ids["ACTIVE_FY_ID"] = fy_a.id

        # Users: real IMAP-capable emails
        system_admin = ensure_user("uat.admin@vavalam.com", "UAT System Admin", ["system_admin"], tenant_a, branch_a)
        firm_admin = ensure_user("uat.firmadmin@vavalam.com", "UAT Firm Admin", ["firm_admin"], tenant_a, branch_a)
        partner = ensure_user("uat.partner@vavalam.com", "UAT Partner", ["partner"], tenant_a, branch_a)
        manager = ensure_user("uat.manager@vavalam.com", "UAT Manager", ["manager"], tenant_a, branch_a)
        staff = ensure_user("uat.staff@vavalam.com", "UAT Staff", ["staff"], tenant_a, branch_a)
        staff2 = ensure_user("uat.staff2@vavalam.com", "UAT Staff 2", ["staff"], tenant_a, branch_a)
        branch2staff = ensure_user("uat.branch2staff@vavalam.com", "UAT Branch 2 Staff", ["staff"], tenant_b, branch_b)
        client_user = ensure_user("uat.client@vavalam.com", "UAT Client User", ["client"], tenant_a, branch_a)
        client2_user = ensure_user("uat.client2@vavalam.com", "UAT Client 2 User", ["client"], tenant_b, branch_b)
        consultant = ensure_user("uat.consultant@vavalam.com", "UAT Consultant", ["consultant"], tenant_a, branch_a)
        invite_user = ensure_user("uat.invite@vavalam.com", "UAT Invite User", ["staff"], tenant_a, branch_a, allow_login=True)
        reset_user = ensure_user("uat.reset@vavalam.com", "UAT Reset User", ["staff"], tenant_a, branch_a, allow_login=True)
        locked_user = ensure_user("uat.lockeduser@vavalam.com", "UAT Locked User", ["staff"], tenant_a, branch_a, locked=True, allow_login=True)

        # Optional but recommended: create one true Tenant B admin for cross-tenant tests.
        # Please create this mailbox if OTP is required for Tenant B Admin login.
        tenant_b_admin = ensure_user("uat.firmadminb@vavalam.com", "UAT Firm Admin B", ["firm_admin"], tenant_b, branch_b)

        for old in LEGACY_EMAIL_MAP:
            if not LEGACY_EMAIL_MAP[old].endswith("@vavalam.com"):
                deactivate_user(old)

        # Employees/staff master records
        ensure_employee("UAT-MGR-A", manager, tenant_a, branch_a, "Branch Manager")
        ensure_employee("UAT-STF-A", staff, tenant_a, branch_a, "Audit Staff")
        ensure_employee("UAT-STF-A2", staff2, tenant_a, branch_a, "Audit Staff")
        ensure_employee("UAT-STF-B", branch2staff, tenant_b, branch_b, "Branch Staff")
        ensure_employee("UAT-LOCK-A", locked_user, tenant_a, branch_a, "Locked Test User")

        # Clients
        client_a, _ = get_or_create(
            Client,
            {"tenant_id": tenant_a.id, "client_code": "UAT-CL-A"},
            {
                "branch_id": branch_a.id,
                "partner_id": partner.id,
                "default_review_partner_user_id": partner.id,
                "portal_user_id": client_user.id,
                "engagement_mode": "hybrid",
                "client_name": "UAT Client A Pvt Ltd",
                "trade_name": "UAT Client A",
                "client_type": "Company",
                "pan": "AABCU1111A",
                "gstin": "33AABCU1111A1Z5",
                "tan": "CHEU12345A",
                "cin_llpin": "U12345TN2025PTC111111",
                "msme_no": "UDYAM-TN-00-0001111",
                "iec_code": "IEC1111111",
                "contact_person_name": "UAT Client A Contact",
                "mobile": "9000000001",
                "email": "uat.client@vavalam.com",
                "alternate_email": "support@vavalam.com",
                "city": "Chennai",
                "state": "Tamil Nadu",
                "pincode": "600001",
                "country": "India",
                "status": "active",
                "client_category": "Regular",
                "risk_category": "Medium",
                "onboarding_date": date.today(),
                "gst_applicable": True,
                "income_tax_applicable": True,
                "tds_applicable": True,
                "roc_applicable": True,
                "audit_applicable": True,
                "is_active": True,
            },
        )
        client_b, _ = get_or_create(
            Client,
            {"tenant_id": tenant_b.id, "client_code": "UAT-CL-B"},
            {
                "branch_id": branch_b.id,
                "partner_id": tenant_b_admin.id,
                "default_review_partner_user_id": tenant_b_admin.id,
                "portal_user_id": client2_user.id,
                "engagement_mode": "hybrid",
                "client_name": "UAT Client B Pvt Ltd",
                "trade_name": "UAT Client B",
                "client_type": "Company",
                "pan": "AABCU2222A",
                "gstin": "33AABCU2222A1Z5",
                "email": "uat.client2@vavalam.com",
                "mobile": "9000000002",
                "city": "Chennai",
                "state": "Tamil Nadu",
                "pincode": "600002",
                "country": "India",
                "status": "active",
                "client_category": "Regular",
                "risk_category": "Low",
                "onboarding_date": date.today(),
                "gst_applicable": True,
                "income_tax_applicable": True,
                "is_active": True,
            },
        )
        ids["CLIENT_A_ID"] = client_a.id
        ids["CLIENT_B_ID"] = client_b.id

        # Service catalogue and task templates
        gst_cat = ensure_service_category("GST", "GST Compliance", 10)
        tax_cat = ensure_service_category("IT", "Income Tax", 20)
        audit_cat = ensure_service_category("AUDIT", "Audit & Assurance", 30)
        roc_cat = ensure_service_category("ROC", "ROC / MCA", 40)

        gst3b = ensure_catalogue("GST-GSTR3B-M", "GSTR-3B Monthly Filing", gst_cat, "monthly", "non_assurance", 10)
        gstr1 = ensure_catalogue("GST-GSTR1-M", "GSTR-1 Monthly Filing", gst_cat, "monthly", "non_assurance", 11)
        itr = ensure_catalogue("IT-ITR-COMP", "Company Income Tax Return", tax_cat, "yearly", "non_assurance", 20)
        audit = ensure_catalogue("AUD-TAX-AUDIT", "Tax Audit", audit_cat, "yearly", "assurance", 30)
        roc = ensure_catalogue("ROC-AOC4-MGT7", "AOC-4 and MGT-7 Filing", roc_cat, "yearly", "non_assurance", 40)
        ids["SERVICE_A_ID"] = gst3b.id

        task_specs = {
            gst3b: [(1, "Collect GST data", "Staff", False, "GST_DATA"), (2, "Prepare GSTR-3B working", "Staff", True, "GST_WORKING"), (3, "Partner review and filing", "Partner", True, "GST_RETURN")],
            gstr1: [(1, "Collect sales register", "Staff", False, "SALES_REGISTER"), (2, "Prepare GSTR-1", "Staff", True, "GST_RETURN")],
            itr: [(1, "Collect financial statements", "Staff", False, "FINANCIALS"), (2, "Prepare computation", "Staff", True, "COMPUTATION"), (3, "Review and file return", "Partner", True, "IT_RETURN")],
            audit: [(1, "Plan audit", "Partner", True, "AUDIT_PLAN"), (2, "Execute audit checklist", "Staff", True, "AUDIT_WORKING"), (3, "Issue audit report", "Partner", True, "AUDIT_REPORT")],
            roc: [(1, "Collect signed financials", "Staff", False, "SIGNED_FS"), (2, "Prepare forms", "Staff", True, "ROC_FORM"), (3, "File MCA forms", "Partner", True, "ROC_CHALLAN")],
        }
        firm_tasks_a = {}
        firm_tasks_b = {}
        for svc, specs in task_specs.items():
            enable_firm_service(tenant_a, branch_a, svc, firm_admin)
            enable_firm_service(tenant_b, branch_b, svc, tenant_b_admin)
            for seq, task_name, role, review, doc_type in specs:
                ensure_default_task(svc, seq, task_name, role, review)
                fta = ensure_firm_task(tenant_a, svc, seq, task_name, role, firm_admin, review)
                ftb = ensure_firm_task(tenant_b, svc, seq, task_name, role, tenant_b_admin, review)
                ensure_doc_requirement(tenant_a, svc, fta, f"{doc_type} Document", doc_type)
                ensure_doc_requirement(tenant_b, svc, ftb, f"{doc_type} Document", doc_type)
                firm_tasks_a[(svc.service_code, seq)] = fta
                firm_tasks_b[(svc.service_code, seq)] = ftb

        gst3b_rule = ensure_due_rule(gst3b, "GSTR-3B due date", "monthly", 20, None, 1)
        gstr1_rule = ensure_due_rule(gstr1, "GSTR-1 due date", "monthly", 11, None, 1)
        itr_rule = ensure_due_rule(itr, "Company ITR due date", "yearly", 31, 10, 0)
        audit_rule = ensure_due_rule(audit, "Tax audit due date", "yearly", 30, 9, 0)
        roc_rule = ensure_due_rule(roc, "ROC annual filing due date", "yearly", 29, 10, 0)

        sel_gst_a = enable_firm_service(tenant_a, branch_a, gst3b, firm_admin)
        sel_gst_b = enable_firm_service(tenant_b, branch_b, gst3b, tenant_b_admin)
        sub_a = ensure_subscription(tenant_a, branch_a, client_a, gst3b, sel_gst_a, partner, manager, staff, gst3b_rule)
        sub_b = ensure_subscription(tenant_b, branch_b, client_b, gst3b, sel_gst_b, tenant_b_admin, tenant_b_admin, branch2staff, gst3b_rule)
        ids["ENGAGEMENT_A_ID"] = sub_a.id
        ids["ENGAGEMENT_B_ID"] = sub_b.id

        task_a = ensure_task_instance(tenant_a, branch_a, client_a, sub_a, gst3b, firm_tasks_a[("GST-GSTR3B-M", 1)], staff, 5)
        ensure_task_instance(tenant_a, branch_a, client_a, sub_a, gst3b, firm_tasks_a[("GST-GSTR3B-M", 2)], staff, 7)
        ensure_task_instance(tenant_a, branch_a, client_a, sub_a, gst3b, firm_tasks_a[("GST-GSTR3B-M", 3)], partner, 9)
        ensure_task_instance(tenant_b, branch_b, client_b, sub_b, gst3b, firm_tasks_b[("GST-GSTR3B-M", 1)], branch2staff, 5)

        # Notice case
        if NoticeCase is not None:
            nc, _ = get_or_create(
                NoticeCase,
                {"reference_no": "UAT-NOTICE-001"},
                {
                    "tenant_id": tenant_a.id,
                    "branch_id": branch_a.id,
                    "client_id": client_a.id,
                    "case_code": "UAT-NC-A-001",
                    "department": "GST",
                    "case_type": "Notice",
                    "title": "UAT GST Notice",
                    "status": "Open",
                    "notice_date": date.today(),
                    "due_date": date.today() + timedelta(days=15),
                    "issue_summary": "Seed notice case for Playwright tests",
                },
            )
            ids["NOTICE_CASE_A_ID"] = nc.id

        # Document storage agent node + sample engagement document/version/job
        secret_hash = hashlib.sha256(LSA_SECRET.encode("utf-8")).hexdigest()
        node_a, _ = get_or_create(
            BranchStorageNode,
            {"tenant_id": tenant_a.id, "branch_id": branch_a.id, "node_code": "UAT-LSA-A"},
            {
                "node_name": "UAT Branch A Local Storage Agent",
                "connector_url": None,
                "secret_key_hash": secret_hash,
                "storage_root_path": "D:/UAT/BranchA/Documents",
                "storage_mode": "pull_jobs",
                "status": "active",
                "is_active": True,
                "quota_limit_bytes": 1024 * 1024 * 1024,
                "used_storage_bytes": 0,
                "subscription_required": False,
                "created_by_user_id": firm_admin.id,
            },
        )
        ids["STORAGE_NODE_A_ID"] = node_a.id

        doc_a, _ = get_or_create(
            EngagementDocument,
            {"tenant_id": tenant_a.id, "engagement_id": sub_a.id, "document_code": "UAT-DOC-A-001"},
            {
                "branch_id": branch_a.id,
                "client_id": client_a.id,
                "task_instance_id": task_a.id,
                "financial_year": ACTIVE_FY,
                "assessment_year": ASSESSMENT_YEAR,
                "document_type": "GST_DATA",
                "title": "UAT GST Working Document",
                "description": "Seeded document for UAT/VAPT tests",
                "current_version_no": 1,
                "status": "active",
                "is_deleted": False,
                "created_by_user_id": staff.id,
                "updated_by_user_id": staff.id,
            },
        )
        sample_hash = hashlib.sha256(b"UAT seeded document content\n").hexdigest()
        ver_a, _ = get_or_create(
            EngagementDocumentVersion,
            {"document_id": doc_a.id, "version_no": 1},
            {
                "tenant_id": tenant_a.id,
                "branch_id": branch_a.id,
                "client_id": client_a.id,
                "engagement_id": sub_a.id,
                "original_filename": "uat-gst-working.txt",
                "stored_filename": "uat-gst-working-v1.txt",
                "content_type": "text/plain",
                "file_size_bytes": len(b"UAT seeded document content\n"),
                "file_hash_sha256": sample_hash,
                "storage_backend": "LOCAL_YEAR_WISE",
                "local_relative_path": "UAT-A/UAT-CL-A/2025-26/uat-gst-working-v1.txt",
                "storage_status": "stored",
                "remarks": "Seeded UAT version",
                "uploaded_by_user_id": staff.id,
            },
        )
        get_or_create(
            DocumentStorageJob,
            {"storage_node_id": node_a.id, "document_id": doc_a.id, "version_id": ver_a.id},
            {
                "tenant_id": tenant_a.id,
                "branch_id": branch_a.id,
                "job_type": "store_version",
                "status": "pending",
                "priority": 5,
                "staging_relative_path": "staging/uat-gst-working-v1.txt",
                "target_relative_path": "UAT-A/UAT-CL-A/2025-26/uat-gst-working-v1.txt",
                "file_size_bytes": ver_a.file_size_bytes,
                "expected_hash_sha256": sample_hash,
                "attempts": 0,
                "created_by_user_id": staff.id,
            },
        )
        ids["TASK_DOCUMENT_A_ID"] = doc_a.id

        db.commit()

        print("\nSeed completed. Paste these into the Playwright .env:\n")
        for k, v in ids.items():
            print(f"{k}={v}")
        print("\nUse these login emails in Playwright .env:")
        print("SYSTEM_ADMIN_EMAIL=uat.admin@vavalam.com")
        print("FIRM_ADMIN_EMAIL=uat.firmadmin@vavalam.com")
        print("PARTNER_EMAIL=uat.partner@vavalam.com")
        print("MANAGER_EMAIL=uat.manager@vavalam.com")
        print("STAFF_EMAIL=uat.staff@vavalam.com")
        print("STAFF2_EMAIL=uat.staff2@vavalam.com")
        print("BRANCH2_STAFF_EMAIL=uat.branch2staff@vavalam.com")
        print("CLIENT_EMAIL=uat.client@vavalam.com")
        print("CLIENT2_EMAIL=uat.client2@vavalam.com")
        print("CONSULTANT_EMAIL=uat.consultant@vavalam.com")
        print("INVITE_TEST_EMAIL=uat.invite@vavalam.com")
        print("RESET_TEST_EMAIL=uat.reset@vavalam.com")
        print("LOCKED_USER_EMAIL=uat.lockeduser@vavalam.com")
        print("TENANT_B_ADMIN_EMAIL=uat.firmadminb@vavalam.com")
        print(f"\nSeed password for all UAT ERP users: {PASSWORD}")
        print(f"Local storage agent test secret: {LSA_SECRET}")
        print("\nNOTE: Create mailbox uat.firmadminb@vavalam.com if OTP login is required for Tenant B Admin tests.")

    except Exception:
        db.rollback()
        raise
    finally:
        db.close()


if __name__ == "__main__":
    main()

