"""
Runs every form's saved test scenarios (Form Designer › Tests) through the
same checks a real submission goes through, and exits non-zero if any fails —
for a CI step before promoting an app, or after changing shared logic.

Each form is tested as its current design (the version the Form Designer
edits) unless --live is given, which tests what people fill in today.

Usage:
    .venv/Scripts/python.exe scripts/run_form_scenarios.py [--tenant <id>] [--live] [--quiet]

Exit codes: 0 all passed (or nothing to run), 1 a scenario failed.
"""

import argparse
import asyncio
import sys
import uuid
from pathlib import Path

sys.path.insert(0, str(Path(__file__).resolve().parents[1]))

from sqlalchemy import select, text  # noqa: E402

from app.core.database import AsyncSessionLocal  # noqa: E402
from app.crud.form_scenarios import run_scenarios  # noqa: E402
from app.crud.form_versions import live_form  # noqa: E402
from app.models.identity import Tenant  # noqa: E402
from app.models.workflow import Form  # noqa: E402


async def main(tenant: str | None, live: bool, quiet: bool) -> int:
    failed = passed = 0
    async with AsyncSessionLocal() as db:
        tenants = (await db.execute(select(Tenant.id, Tenant.name).order_by(Tenant.name))).all()
    if tenant:
        tenants = [t for t in tenants if str(t.id) == tenant]
        if not tenants:
            print(f"No tenant {tenant}.", file=sys.stderr)
            return 1
    for tenant_id, tenant_name in tenants:
        # One session per tenant, scoped to it (row-level security, db/schema.sql).
        async with AsyncSessionLocal() as db:
            await db.execute(text("SELECT set_config('app.current_tenant_id', :v, true)"), {"v": str(tenant_id)})
            current = (
                await db.execute(select(Form).where(Form.tenant_id == tenant_id, Form.is_current.is_(True)).order_by(Form.name))
            ).scalars().all()
            for form in current:
                if live:
                    form = await live_form(db, tenant_id, form.form_id) or form
                scenarios = (form.settings or {}).get("test_scenarios") or []
                if not scenarios:
                    continue
                results = await run_scenarios(db, tenant_id, form.field_definitions or [], scenarios)
                for r in results:
                    if r.passed:
                        passed += 1
                        if not quiet:
                            print(f"PASS  {tenant_name} › {form.name} v{form.version} › {r.name}")
                    else:
                        failed += 1
                        print(f"FAIL  {tenant_name} › {form.name} v{form.version} › {r.name}")
                        for f in r.failures:
                            print(f"        {f}")
            await db.rollback()  # nothing is written; make that explicit
    print(f"\n{passed} passed, {failed} failed.")
    return 1 if failed else 0


if __name__ == "__main__":
    parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
    parser.add_argument("--tenant", help="only this tenant id")
    parser.add_argument("--live", action="store_true", help="test the live (published) version of each form")
    parser.add_argument("--quiet", action="store_true", help="print failures only")
    args = parser.parse_args()
    if args.tenant:
        uuid.UUID(args.tenant)
    sys.exit(asyncio.run(main(args.tenant, args.live, args.quiet)))
