"""
Company (Tenant) API
--------------------
- POST /companies/register     Public — first-time setup, creates company + head-office branch + admin user
- GET  /companies/me           Returns the current user's company
- PATCH /companies/me          Update company profile (logo, contact, footer text…)
- GET  /companies/lookup/{code} Public — resolve a company_code to basic info for the login page
- GET  /companies/check-setup  Returns whether any company exists (used by setup wizard gate)
"""
import uuid
import re
from datetime import datetime, timedelta
from typing import Optional

from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session
from app.core.database import get_db
from app.core.dependencies import get_current_user
from app.core.security import get_password_hash
from app.models.company import Company
from app.models.branch import Branch
from app.models.user import User
from app.constants.industry_accounts import get_industry_codes
from scripts.seeds.seed_accounts import IFRS_COA, PARENTS
from app.schemas.company import (
    CompanyCreate, CompanyUpdate, CompanyResponse,
    CompanyPublicResponse, CompanyRegistrationResult,
    CompanyFullSetup, CompanyFullSetupResult,
    BranchSetup, UserSetup, OpeningBalanceEntry,
)

router = APIRouter()


def _completed_tenant_count(db: Session) -> int:
    return (
        db.query(Company)
        .filter(Company.is_active == True, Company.is_setup_complete == True)
        .count()
    )


def _allows_additional_tenant_setup(app_settings) -> bool:
    """Cloud/licensed hub: each new company uses its own CNP license in the setup wizard."""
    return bool(app_settings.license_required_for_setup)


def _username_taken_globally(db: Session, username: str) -> bool:
    """Legacy single-tenant check — only when additional tenants are not allowed."""
    return (
        db.query(User)
        .filter(User.username == username)
        .first()
        is not None
    )


def _generate_company_code(name: str, db: Session) -> str:
    """Derive a unique 4-6 char company code from the company name."""
    base = re.sub(r"[^A-Z0-9]", "", name.upper())[:6] or "CO"
    code = base
    suffix = 1
    while db.query(Company).filter(Company.company_code == code).first():
        code = f"{base[:5]}{suffix}"
        suffix += 1
    return code


# ── Public: check if any company exists (gate for /setup page) ───────────────

@router.get("/check-setup")
def check_setup(db: Session = Depends(get_db)):
    """Returns whether the system has been initialised with at least one company."""
    from app.core.config import settings as app_settings

    active_count = db.query(Company).filter(Company.is_active == True).count()
    complete_count = (
        db.query(Company)
        .filter(Company.is_active == True, Company.is_setup_complete == True)
        .count()
    )
    from app.services.licensing_service import uses_cloud_license_authority

    allow_more = complete_count > 0 and _allows_additional_tenant_setup(app_settings)

    return {
        "setup_required": complete_count == 0,
        "allow_additional_tenant": allow_more,
        "company_count": active_count,
        "setup_complete_count": complete_count,
        "license_required_for_setup": app_settings.license_required_for_setup,
        "deployment_mode": app_settings.deployment_mode,
        "license_cloud_url": app_settings.license_cloud_url,
        "erp_public_url": app_settings.erp_public_url,
        "requires_cloud_license": uses_cloud_license_authority(),
    }


# ── Public: lookup company by code (for login page) ──────────────────────────

@router.get("/lookup/{company_code}", response_model=CompanyPublicResponse)
def lookup_company(company_code: str, db: Session = Depends(get_db)):
    company = db.query(Company).filter(
        Company.company_code == company_code.upper(),
        Company.is_active == True,
    ).first()
    if not company:
        raise HTTPException(status_code=404, detail="Company not found")
    return company


# ── Public: register a new company (setup wizard) ────────────────────────────

def _enforce_license_for_setup(payload, deployment: str, license_svc, app_settings) -> None:
    from app.services.licensing_service import uses_cloud_license_authority

    if not app_settings.license_required_for_setup:
        return

    if not payload.license_key or not str(payload.license_key).strip():
        raise HTTPException(
            status_code=400,
            detail="A CNP license key is required. Enter the purchase token from CNP Solutions.",
        )

    if uses_cloud_license_authority():
        if not getattr(payload, "setup_token", None) or not str(payload.setup_token).strip():
            raise HTTPException(
                status_code=400,
                detail="Validate your license in the setup wizard (step 1) before continuing.",
            )
        verify = license_svc.verify_setup_with_cloud(
            payload.license_key,
            payload.setup_token,
            deployment=deployment,
        )
        if not verify.get("valid"):
            raise HTTPException(
                status_code=400,
                detail=verify.get("message", "License validation expired. Validate again in step 1."),
            )

    check = license_svc.validate_for_setup(payload.license_key, deployment=deployment)
    if not check.get("valid"):
        raise HTTPException(status_code=400, detail=check.get("message", "Invalid license key"))


@router.post("/register", response_model=CompanyRegistrationResult, status_code=status.HTTP_201_CREATED)
def register_company(payload: CompanyCreate, db: Session = Depends(get_db)):
    """
    Basic first-time registration (use /register-full for the full wizard).
    Only available when no company exists yet.
    """
    from app.core.config import settings as app_settings
    from app.services.licensing_service import LicensingService
    from app.utils.user_email import normalize_user_email

    if app_settings.license_required_for_setup:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail=(
                "A valid CNP license is required. Use the setup wizard at /setup "
                "(POST /companies/register-full with license key)."
            ),
        )

    if _completed_tenant_count(db) > 0 and not _allows_additional_tenant_setup(app_settings):
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="System already configured. Use the authenticated API to manage companies."
        )
    # Validate unique company code
    company_code = payload.company_code or _generate_company_code(payload.name, db)
    if db.query(Company).filter(Company.company_code == company_code).first():
        raise HTTPException(status_code=400, detail=f"Company code '{company_code}' is already taken")

    if _completed_tenant_count(db) == 0 and _username_taken_globally(db, payload.admin_username):
        raise HTTPException(status_code=400, detail=f"Username '{payload.admin_username}' is already taken")

    company_id = str(uuid.uuid4())
    branch_id = str(uuid.uuid4())
    admin_id = str(uuid.uuid4())

    # 1. Company
    company = Company(
        id=company_id,
        name=payload.name,
        legal_name=payload.legal_name or payload.name,
        company_code=company_code,
        registration_number=payload.registration_number,
        tax_identification_number=payload.tax_identification_number,
        vat_registration_number=payload.vat_registration_number,
        industry=payload.industry,
        address_line1=payload.address_line1,
        address_line2=payload.address_line2,
        city=payload.city,
        state=payload.state,
        country=payload.country or "Botswana",
        postal_code=payload.postal_code,
        phone=payload.phone,
        phone2=payload.phone2,
        fax=payload.fax,
        email=payload.email,
        website=payload.website,
        logo_url=payload.logo_url,
        primary_color=payload.primary_color or "#0d6efd",
        currency=payload.currency or "BWP",
        default_vat_rate=payload.default_vat_rate or 14.0,
        fiscal_year_start_month=payload.fiscal_year_start_month or 1,
        timezone=payload.timezone or "Africa/Gaborone",
        invoice_footer=payload.invoice_footer,
        receipt_footer=payload.receipt_footer,
        po_terms=payload.po_terms,
        subscription_plan=payload.subscription_plan or "standard",
        is_active=True,
        is_setup_complete=True,
        setup_completed_at=datetime.utcnow(),
    )
    db.add(company)

    # 2. Head-office branch
    branch_code = f"{company_code}-HQ"
    # Ensure branch code is unique (unlikely collision but safe)
    bc_suffix = 1
    while db.query(Branch).filter(Branch.code == branch_code).first():
        branch_code = f"{company_code}-HQ{bc_suffix}"
        bc_suffix += 1

    branch = Branch(
        id=branch_id,
        company_id=company_id,
        name=f"{payload.name} — Head Office",
        code=branch_code,
        phone=payload.phone,
        email=payload.email,
        address=payload.address_line1,
        country=payload.country or "Botswana",
        is_head_office=True,
        active=True,
        vat_registration_number=payload.vat_registration_number,
        currency=payload.currency or "BWP",
        timezone=payload.timezone or "Africa/Gaborone",
    )
    db.add(branch)

    # 3. Super-admin user
    hashed = get_password_hash(payload.admin_password)
    admin = User(
        id=admin_id,
        company_id=company_id,
        branch_id=branch_id,
        username=payload.admin_username,
        password_digest=hashed,
        role="super_admin",
        email=normalize_user_email(payload.admin_email),
        first_name=payload.admin_first_name or payload.admin_username,
        last_name=payload.admin_last_name or "",
        active=True,
    )
    db.add(admin)
    db.commit()
    db.refresh(company)

    # 4. Default fiscal year for the new company (calendar or configured start month)
    try:
        from app.services.fiscal_period_service import FiscalPeriodService
        FiscalPeriodService(db).bootstrap_default_fiscal_year(
            branch_id=branch_id,
            start_month=payload.fiscal_year_start_month or 1,
            user_id=admin_id,
            activate=True,
        )
    except Exception as exc:
        import logging
        logging.getLogger(__name__).warning(
            "Could not bootstrap fiscal year during company setup: %s", exc
        )

    return CompanyRegistrationResult(
        company=CompanyResponse.model_validate(company),
        admin_user_id=admin_id,
        admin_username=payload.admin_username,
        message=f"Company '{company.name}' registered. Login with company code: {company_code}",
    )


# ── Authenticated: get / update own company ──────────────────────────────────

@router.get("/me", response_model=CompanyResponse)
def get_my_company(
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db),
):
    company_id = getattr(current_user, "company_id", None)
    if not company_id:
        # Fall back: find company via user's branch
        if current_user.branch_id:
            branch = db.query(Branch).filter(Branch.id == current_user.branch_id).first()
            if branch:
                company_id = branch.company_id
    if not company_id:
        raise HTTPException(status_code=404, detail="No company associated with this account")
    company = db.query(Company).filter(Company.id == company_id).first()
    if not company:
        raise HTTPException(status_code=404, detail="Company not found")
    return company


@router.patch("/me", response_model=CompanyResponse)
def update_my_company(
    payload: CompanyUpdate,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db),
):
    company_id = getattr(current_user, "company_id", None)
    if not company_id and current_user.branch_id:
        branch = db.query(Branch).filter(Branch.id == current_user.branch_id).first()
        if branch:
            company_id = branch.company_id

    if not company_id:
        raise HTTPException(status_code=404, detail="No company associated with this account")

    company = db.query(Company).filter(Company.id == company_id).first()
    if not company:
        raise HTTPException(status_code=404, detail="Company not found")

    update_data = payload.model_dump(exclude_unset=True, exclude_none=True)
    # Protect company_code from being changed after registration
    update_data.pop("company_code", None)

    for field, value in update_data.items():
        setattr(company, field, value)

    db.commit()
    db.refresh(company)
    return company


# ── Public: full setup wizard (atomic) ───────────────────────────────────────

@router.post("/register-full", response_model=CompanyFullSetupResult, status_code=status.HTTP_201_CREATED)
def register_company_full(payload: CompanyFullSetup, db: Session = Depends(get_db)):
    """
    Complete wizard registration.
    First tenant: no license required when license_required_for_setup is off (dev).
    Cloud hub: each additional tenant needs its own unused CNP license key (validated in step 1).
    Creates atomically: company · branches · admin user · team · chart of accounts · opening balances.
    """
    from app.models.accounting import AccountingCode, JournalEntry, AccountingEntry
    from decimal import Decimal
    from app.core.config import settings as app_settings
    from app.services.licensing_service import LicensingService
    from app.utils.user_email import normalize_user_email

    if _completed_tenant_count(db) > 0 and not _allows_additional_tenant_setup(app_settings):
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail=(
                "System is already configured. This endpoint is only available during "
                "initial setup. To add a new company, contact your system administrator."
            )
        )

    # ── Validate uniqueness ──
    company_code = payload.company_code or _generate_company_code(payload.name, db)
    if db.query(Company).filter(Company.company_code == company_code).first():
        raise HTTPException(status_code=400, detail=f"Company code '{company_code}' already taken")

    seen_usernames = set()
    for uname in [payload.admin_username] + [u.username for u in (payload.additional_users or [])]:
        if uname in seen_usernames:
            raise HTTPException(status_code=400, detail=f"Duplicate username '{uname}' in this setup")
        seen_usernames.add(uname)

    if _completed_tenant_count(db) == 0:
        if _username_taken_globally(db, payload.admin_username):
            raise HTTPException(status_code=400, detail=f"Username '{payload.admin_username}' already taken")
        for u in (payload.additional_users or []):
            if _username_taken_globally(db, u.username):
                raise HTTPException(status_code=400, detail=f"Username '{u.username}' already taken")

    deployment = (payload.deployment or app_settings.deployment_mode or "cloud").lower()
    license_svc = LicensingService(db)
    _enforce_license_for_setup(payload, deployment, license_svc, app_settings)
    branches_to_create = 1 + len(payload.additional_branches or [])
    try:
        license_svc.assert_setup_branch_quota(
            payload.license_key,
            deployment,
            branches_to_create,
        )
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))

    company_id = str(uuid.uuid4())
    hq_branch_id = str(uuid.uuid4())

    # ── 1. Company ──
    company = Company(
        id=company_id,
        name=payload.name,
        legal_name=payload.legal_name or payload.name,
        company_code=company_code,
        registration_number=payload.registration_number,
        tax_identification_number=payload.tax_identification_number,
        vat_registration_number=payload.vat_registration_number,
        industry=payload.industry,
        address_line1=payload.address_line1,
        address_line2=payload.address_line2,
        city=payload.city,
        state=payload.state,
        country=payload.country or "Botswana",
        postal_code=payload.postal_code,
        phone=payload.phone,
        email=payload.email,
        website=payload.website,
        logo_url=payload.logo_url,
        primary_color=payload.primary_color or "#0d6efd",
        currency=payload.currency or "BWP",
        default_vat_rate=payload.default_vat_rate or 14.0,
        fiscal_year_start_month=payload.fiscal_year_start_month or 1,
        timezone=payload.timezone or "Africa/Gaborone",
        invoice_footer=payload.invoice_footer,
        receipt_footer=payload.receipt_footer,
        po_terms=payload.po_terms,
        subscription_plan=payload.subscription_plan or "standard",
        is_active=True,
        is_setup_complete=True,
        setup_completed_at=datetime.utcnow(),
    )
    db.add(company)

    # ── 2. Head-Office Branch ──
    hq_code = f"{company_code}-HQ"
    while db.query(Branch).filter(Branch.code == hq_code).first():
        hq_code += "1"
    hq_branch = Branch(
        id=hq_branch_id,
        company_id=company_id,
        name=f"{payload.name} — Head Office",
        code=hq_code,
        phone=payload.phone,
        email=payload.email,
        address=payload.address_line1,
        country=payload.country or "Botswana",
        is_head_office=True,
        active=True,
        vat_registration_number=payload.vat_registration_number,
        currency=payload.currency or "BWP",
        timezone=payload.timezone or "Africa/Gaborone",
    )
    db.add(hq_branch)

    # ── 3. Super-Admin ──
    admin_id = str(uuid.uuid4())
    admin = User(
        id=admin_id,
        company_id=company_id,
        branch_id=hq_branch_id,
        username=payload.admin_username,
        password_digest=get_password_hash(payload.admin_password),
        role="super_admin",
        email=normalize_user_email(payload.admin_email),
        first_name=payload.admin_first_name or payload.admin_username,
        last_name=payload.admin_last_name or "",
        active=True,
    )
    db.add(admin)
    db.flush()  # persist so branch codes are available below

    # ── 4. Additional Branches ──
    branch_code_map: dict[str, str] = {hq_code: hq_branch_id}  # code -> id
    for b in (payload.additional_branches or []):
        bid = str(uuid.uuid4())
        bc = (b.code or re.sub(r"[^A-Z0-9]", "", b.name.upper())[:8]) + ""
        # Ensure uniqueness within this request and DB
        suffix = 1
        base_bc = bc
        while db.query(Branch).filter(Branch.code == bc).first() or bc in branch_code_map:
            bc = f"{base_bc[:7]}{suffix}"
            suffix += 1
        new_branch = Branch(
            id=bid,
            company_id=company_id,
            name=b.name,
            code=bc,
            address=b.address,
            phone=b.phone,
            email=b.email,
            is_head_office=False,
            active=True,
            currency=payload.currency or "BWP",
            timezone=payload.timezone or "Africa/Gaborone",
        )
        db.add(new_branch)
        branch_code_map[bc] = bid
    db.flush()

    # ── 5. Additional Users ──
    VALID_ROLES = {"super_admin", "admin", "accountant", "manager", "cashier", "staff"}
    users_created = 1  # count the admin
    for u in (payload.additional_users or []):
        role = u.role if u.role in VALID_ROLES else "staff"
        # Resolve branch: by code if given, otherwise HQ
        assigned_branch_id = hq_branch_id
        if u.branch_code and u.branch_code in branch_code_map:
            assigned_branch_id = branch_code_map[u.branch_code]
        new_user = User(
            id=str(uuid.uuid4()),
            company_id=company_id,
            branch_id=assigned_branch_id,
            username=u.username,
            password_digest=get_password_hash(u.password),
            role=role,
            email=normalize_user_email(u.email),
            first_name=u.first_name or u.username,
            last_name=u.last_name or "",
            active=True,
        )
        db.add(new_user)
        users_created += 1
    db.flush()

    # ── 6. Company Walk-in Customer ─────────────────────────────────────────
    # Use the single global walk-in customer (seeded at app startup). Do not create
    # a per-company duplicate — that caused two identical "Walk-in Customer" rows.
    from app.constants.walkin_customer import WALKIN_CUSTOMER_ID
    from scripts.seeds.seed_walkin_customer import seed_walkin_customer

    seed_walkin_customer(db)
    walkin_id = WALKIN_CUSTOMER_ID
    if hasattr(company, "walkin_customer_id"):
        company.walkin_customer_id = walkin_id
    db.flush()

    # ── 7. Industry-filtered Chart of Accounts ──────────────────────────────
    # Reuse global IFRS codes seeded at startup (code is globally unique). Only
    # insert rows that are missing so setup does not collide with seed_accounts.
    from app.models.accounting import AccountingCode as AC

    industry_codes = get_industry_codes(payload.industry)
    coa_rows = IFRS_COA if industry_codes is None else [r for r in IFRS_COA if r[0] in industry_codes]

    existing_by_code: dict[str, AC] = {c.code: c for c in db.query(AC).all()}
    ac_map: dict[str, AC] = {}
    accounts_created = 0
    for code, name, a_type, cat, is_par, rtag in coa_rows:
        if code in existing_by_code:
            ac_map[code] = existing_by_code[code]
            continue
        obj = AC(
            id=str(uuid.uuid4()),
            code=code,
            name=name,
            account_type=a_type,
            category=cat,
            is_parent=is_par,
            reporting_tag=rtag,
            branch_id=hq_branch_id,
            balance=0.0,
            total_debits=0.0,
            total_credits=0.0,
        )
        db.add(obj)
        db.flush()
        existing_by_code[code] = obj
        ac_map[code] = obj
        accounts_created += 1

    # Wire parent links for any new codes (globals are already wired by seed)
    for child_code, parent_code in PARENTS.items():
        child = ac_map.get(child_code)
        parent = ac_map.get(parent_code)
        if child and parent and child.parent_id != parent.id:
            child.parent_id = parent.id

    parent_ids = {obj.parent_id for obj in ac_map.values() if obj.parent_id}
    for obj in ac_map.values():
        obj.is_parent = obj.id in parent_ids
    db.flush()

    if not accounts_created:
        accounts_created = len(ac_map)

    # ── 7. Opening Balances ──
    ob_count = 0
    balances = payload.opening_balances or []
    if balances:
        # Filter to entries that have a value
        active_balances = [b for b in balances if (b.debit or 0) != 0 or (b.credit or 0) != 0]
        if active_balances:
            total_debits = sum(Decimal(str(b.debit or 0)) for b in active_balances)
            total_credits = sum(Decimal(str(b.credit or 0)) for b in active_balances)
            # Auto-balance: if debits != credits, add a balancing entry to Retained Earnings (3210)
            diff = total_debits - total_credits
            if abs(diff) > Decimal("0.005"):
                re_ac = ac_map.get("3210")
                if re_ac:
                    if diff > 0:
                        active_balances.append(OpeningBalanceEntry(
                            account_code="3210", credit=float(diff),
                            description="Auto-balance to Retained Earnings"
                        ))
                    else:
                        active_balances.append(OpeningBalanceEntry(
                            account_code="3210", debit=float(abs(diff)),
                            description="Auto-balance to Retained Earnings"
                        ))

            ref = f"OB-{company_code}-{datetime.utcnow().strftime('%Y%m%d')}"
            ae = AccountingEntry(
                id=str(uuid.uuid4()),
                branch_id=hq_branch_id,
                particulars="Opening Balances",
                book="General",
                status="posted",
                date_prepared=datetime.utcnow().date(),
            )
            db.add(ae)
            db.flush()

            for b in active_balances:
                ac = ac_map.get(b.account_code)
                if not ac:
                    continue
                dr = Decimal(str(b.debit or 0))
                cr = Decimal(str(b.credit or 0))
                je = JournalEntry(
                    id=str(uuid.uuid4()),
                    accounting_entry_id=ae.id,
                    accounting_code_id=ac.id,
                    branch_id=hq_branch_id,
                    narration=b.description or f"Opening balance — {ac.name}",
                    debit_amount=dr,
                    credit_amount=cr,
                    date=datetime.utcnow().date(),
                    reference=ref,
                    entry_type="Opening Balance",
                    origin="Setup Wizard",
                )
                db.add(je)
                ac.total_debits = Decimal(str(ac.total_debits or 0)) + dr
                ac.total_credits = Decimal(str(ac.total_credits or 0)) + cr
                ac.balance = Decimal(str(ac.balance or 0)) + dr - cr
                ob_count += 1

    if payload.license_key and str(payload.license_key).strip():
        try:
            license_svc.activate_for_company(
                payload.license_key,
                company,
                activated_by_email=payload.admin_email or payload.email,
                deployment=deployment,
            )
        except ValueError as exc:
            db.rollback()
            raise HTTPException(status_code=400, detail=str(exc))

        from app.services.licensing_service import uses_cloud_license_authority

        if uses_cloud_license_authority() and payload.setup_token:
            claim = license_svc.claim_setup_on_cloud(
                payload.license_key,
                payload.setup_token,
                deployment=deployment,
                site_name=payload.name,
            )
            if not claim.get("success"):
                db.rollback()
                raise HTTPException(
                    status_code=400,
                    detail=claim.get("message", "Could not register license with CNP cloud."),
                )

    try:
        db.commit()
    except Exception as exc:
        db.rollback()
        from sqlalchemy.exc import IntegrityError

        if isinstance(exc, IntegrityError):
            err = str(getattr(exc, "orig", exc)).lower()
            if "users_email" in err or "email" in err and "unique" in err:
                detail = (
                    "A user with this email already exists for another organisation. "
                    "Use a different email or leave email blank."
                )
            elif "username" in err and "unique" in err:
                detail = (
                    "This username is already used on the server. "
                    "Choose a different username for the admin or team member."
                )
            else:
                detail = (
                    "Setup could not be saved because some data already exists "
                    "(company code, username, email, or accounts). "
                    "Change conflicting values and try again."
                )
            raise HTTPException(status_code=400, detail=detail) from exc
        raise

    db.refresh(company)

    from app.constants.industry_accounts import get_industry_label
    industry_label = get_industry_label(payload.industry)

    cloud_mirror_success = None
    cloud_login_url = None
    cloud_mirror_message = None
    setup_message = (
        f"Setup complete! '{company.name}' ({industry_label}) is ready. "
        f"{accounts_created} accounts · {len(branch_code_map)} branch(es) · "
        f"{users_created} user(s). Login with company code '{company_code}'."
    )

    if (
        deployment in ("local", "hybrid")
        and app_settings.auto_provision_cloud_mirror
        and app_settings.cloud_sync_enabled
        and payload.license_key
        and payload.setup_token
    ):
        from app.services.licensing_service import uses_cloud_license_authority
        from app.services.cloud_mirror_service import link_local_server_after_setup

        if uses_cloud_license_authority():
            ac_payload = [
                {
                    "id": ac.id,
                    "code": ac.code,
                    "name": ac.name,
                    "account_type": ac.account_type,
                    "category": ac.category,
                    "is_parent": ac.is_parent,
                    "reporting_tag": ac.reporting_tag,
                    "balance": float(ac.balance or 0),
                }
                for ac in ac_map.values()
            ]
            mirror = link_local_server_after_setup(
                license_key=payload.license_key,
                setup_token=payload.setup_token,
                cloud_url=app_settings.license_cloud_url or "",
                company_id=company_id,
                company_code=company_code,
                company_name=company.name,
                admin_user_id=admin_id,
                admin_username=payload.admin_username,
                admin_password_digest=admin.password_digest,
                hq_branch_id=hq_branch_id,
                hq_branch_code=hq_code,
                legal_name=company.legal_name,
                admin_email=payload.admin_email,
                admin_first_name=payload.admin_first_name,
                admin_last_name=payload.admin_last_name,
                phone=payload.phone,
                email=payload.email,
                industry=payload.industry,
                currency=payload.currency or "BWP",
                accounting_codes=ac_payload,
                public_base_url=None,
                node_name=company.name,
            )
            cloud_mirror_success = mirror.get("success")
            cloud_mirror_message = mirror.get("message")
            cloud_login_url = mirror.get("cloud_login_url") or (
                mirror.get("provision") or {}
            ).get("cloud_login_url")
            if cloud_mirror_success:
                setup_message += (
                    f" Cloud backup mirror is ready — use the same company code and admin password at "
                    f"{cloud_login_url or 'your cloud hub'}."
                )
            elif cloud_mirror_message:
                setup_message += (
                    f" Note: cloud mirror could not be created ({cloud_mirror_message}). "
                    "LAN sync can be configured later in Settings → Cloud Sync."
                )

    return CompanyFullSetupResult(
        company=CompanyResponse.model_validate(company),
        company_code=company_code,
        admin_username=payload.admin_username,
        admin_password_hint=f"{payload.admin_password[:2]}{'*' * (len(payload.admin_password) - 2)}",
        branches_created=len(branch_code_map),
        users_created=users_created,
        accounts_created=accounts_created,
        opening_balance_entries=ob_count,
        walkin_customer_id=walkin_id,
        message=setup_message,
        cloud_mirror_success=cloud_mirror_success,
        cloud_login_url=cloud_login_url,
        cloud_mirror_message=cloud_mirror_message,
    )


# ── Helper used by other services ────────────────────────────────────────────

def get_company_for_branch(branch_id: Optional[str], db: Session) -> Optional[Company]:
    """Resolve a branch_id → Company.  Returns None if branch has no company."""
    if not branch_id:
        return None
    branch = db.query(Branch).filter(Branch.id == branch_id).first()
    if not branch or not branch.company_id:
        return None
    return db.query(Company).filter(Company.id == branch.company_id).first()
