"""
Provisions a new tenant: the tenant row, the five baseline roles from
FlowFabric_SRS.docx Section 9 (with Administrator flagged is_system_role,
matching FR-RBA-005's "fixed and non-reducible") plus a sixth "Portal" role
for Public Portal (vendor) accounts, and a first Administrator user.

This is deliberately a script, not a REST endpoint: there is no POST
/tenants route (see app/routers/tenants.py) because the `tenants` table
carries no tenant_id column of its own and therefore no Row-Level Security
policy — nothing at the database layer would stop a tenant-scoped API
caller from creating or enumerating other tenants. Provisioning a tenant is
a platform-onboarding operation performed by internal platform staff (SRS
3.6: "Customer organizations will designate at least one Administrator
during onboarding..."), run directly against the database, not through the
per-tenant API surface every other route in this app is scoped to.

Usage:
    .venv/Scripts/python.exe scripts/provision_tenant.py \\
        --tenant-name "Acme Corp" \\
        --admin-name "Alice Admin" \\
        --admin-email alice@acme-corp.com \\
        [--admin-password "..."]   # omit to auto-generate one, printed once below
"""

import argparse
import asyncio
import secrets
import sys
from datetime import date, datetime, timezone
from pathlib import Path

sys.path.insert(0, str(Path(__file__).resolve().parent.parent))

from sqlalchemy import text  # noqa: E402

from app.core.auth import hash_password  # noqa: E402
from app.core.database import AsyncSessionLocal  # noqa: E402
from app.crud.tenant_provisioning import seed_baseline_roles  # noqa: E402
from app.models.identity import Tenant, User, UserRole  # noqa: E402


async def provision(tenant_name: str, admin_name: str, admin_email: str, admin_password: str | None, license_: dict | None) -> None:
    generated_password = admin_password is None
    password = admin_password or secrets.token_urlsafe(12)

    async with AsyncSessionLocal() as db:
        async with db.begin():
            tenant = Tenant(name=tenant_name, status="active")
            if license_ is not None:
                # A tenant can't be used without a license (app/crud/licensing.py).
                tenant.license_set_at = datetime.now(timezone.utc)
                tenant.license_max_users = license_["max_users"]
                tenant.license_ends_on = license_["ends_on"]
            db.add(tenant)
            await db.flush()
            # Everything after this is the new tenant's own (row-level security, db/schema.sql).
            await db.execute(text("SELECT set_config('app.current_tenant_id', :v, true)"), {"v": str(tenant.id)})

            roles = await seed_baseline_roles(db, tenant.id)

            admin_user = User(
                tenant_id=tenant.id,
                name=admin_name,
                email=admin_email,
                password_hash=hash_password(password),
                status="active",
            )
            db.add(admin_user)
            await db.flush()

            db.add(UserRole(user_id=admin_user.id, role_id=roles["Administrator"].id))
            await db.flush()

            print(f"tenant_id={tenant.id}")
            print(f"admin_user_id={admin_user.id}")
            if generated_password:
                print(f"admin_password={password}  # generated — record this now, it is not stored in plaintext anywhere")
            for name, role in roles.items():
                print(f"role[{name}]={role.id}")
            if license_ is None:
                print("# No license: nobody can sign in until the Super Admin sets one (Tenants → License) or a license file is applied.")


def main() -> None:
    parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
    parser.add_argument("--tenant-name", required=True)
    parser.add_argument("--admin-name", required=True)
    parser.add_argument("--admin-email", required=True)
    parser.add_argument("--admin-password", default=None, help="omit to auto-generate and print one")
    lic = parser.add_argument_group("license (without one, nobody can sign in)")
    lic.add_argument("--licensed", action="store_true", help="license it now; with no limits unless given below")
    lic.add_argument("--max-users", type=int, default=None, help="active Studio accounts")
    lic.add_argument("--license-ends-on", type=date.fromisoformat, default=None, help="YYYY-MM-DD, valid through that day (UTC)")
    args = parser.parse_args()
    license_ = None
    if args.licensed or args.max_users is not None or args.license_ends_on is not None:
        license_ = {"max_users": args.max_users, "ends_on": args.license_ends_on}
    asyncio.run(provision(args.tenant_name, args.admin_name, args.admin_email, args.admin_password, license_))


if __name__ == "__main__":
    main()
