"""Seeded mini-graph for the authz tests (04-architecture: "test
fixtures are small slices of the same graph, so tests speak the
business's language"). SQLite is enough here — the authz engine uses
portable constructs; the reporting SQL runs against Postgres in
tests/reporting."""

from types import SimpleNamespace

import pytest
from sqlalchemy import create_engine
from sqlalchemy.orm import Session
from sqlalchemy.pool import StaticPool

from app.models import Base, Engagement, ImportBatch, Party, Tenant, TimeEntry, User
from app.services.authz.context import resolve_actor

TENANT_SLUG = "bowden-works"


def _party(session, kind, name, slug):
    party = Party(kind=kind, name=name, slug=slug)
    session.add(party)
    session.flush()
    return party


@pytest.fixture()
def graph():
    """tenant BW; rian = owner + super admin; adi = manager-grade
    subcontract; gary = plain worker; mallory = user with no party;
    a second tenant (Tingang) with one entry for cross-tenant checks."""
    engine = create_engine(
        "sqlite://", connect_args={"check_same_thread": False}, poolclass=StaticPool
    )
    Base.metadata.create_all(engine)
    s = Session(engine)

    bw = _party(s, "org", "Bowden Works", TENANT_SLUG)
    tingang = _party(s, "org", "Tingang", "tingang")
    tenant = Tenant(party_id=bw.id, settings={})
    tenant2 = Tenant(party_id=tingang.id, settings={})
    s.add_all([tenant, tenant2])
    s.flush()

    p_rian = _party(s, "person", "Rian Bowden", "rian-bowden")
    p_adi = _party(s, "person", "Adi Pramono", "adi-pramono")
    p_gary = _party(s, "person", "Gary", "gary")

    users = {
        "rian": User(
            idauth_username="rian", email="rian@rian.ca",
            person_party_id=p_rian.id, is_super_admin=True,
        ),
        "adi": User(
            idauth_username="adi", email="info@adipramono.com",
            person_party_id=p_adi.id,
        ),
        "gary": User(idauth_username="gary", email="gary@rian.ca",
                     person_party_id=p_gary.id),
        "mallory": User(idauth_username="mallory", email="m@example.com"),
    }
    s.add_all(users.values())
    s.flush()

    s.add_all(
        [
            Engagement(
                tenant_id=tenant.id, type="official_partnership",
                party_a_id=bw.id, party_b_id=p_rian.id,
                role_a="owner", role_b="owner",
            ),
            Engagement(
                tenant_id=tenant.id, type="subcontract",
                party_a_id=bw.id, party_b_id=p_rian.id,
                role_a="prime", role_b="subcontractor",
            ),
            Engagement(
                tenant_id=tenant.id, type="subcontract",
                party_a_id=bw.id, party_b_id=p_adi.id,
                role_a="prime", role_b="subcontractor", can_manage_imports=True,
            ),
            Engagement(
                tenant_id=tenant.id, type="subcontract",
                party_a_id=bw.id, party_b_id=p_gary.id,
                role_a="prime", role_b="subcontractor",
            ),
        ]
    )
    s.flush()

    batches = {
        "adi": ImportBatch(tenant_id=tenant.id, imported_by=users["adi"].id,
                           source="clockify", name="adi batch"),
        "rian": ImportBatch(tenant_id=tenant.id, imported_by=users["rian"].id,
                            source="clockify", name="rian batch"),
        "orphan": ImportBatch(tenant_id=tenant.id, imported_by=None,
                              source="toggl", name="orphan batch"),
    }
    s.add_all(batches.values())
    s.flush()

    from datetime import datetime

    def entry(batch_key, tenant_id=tenant.id, **kw):
        return TimeEntry(
            tenant_id=tenant_id,
            source="clockify",
            import_id=batches[batch_key].id if batch_key else None,
            start_at=datetime(2026, 6, 1, 9, 0, 0),
            **kw,
        )

    entries = [
        entry("adi", description="adi row 1"),
        entry("adi", description="adi row 2"),
        entry("rian", description="rian row"),
        entry("orphan", description="orphan-batch row"),
        entry(None, description="manual row (no batch)"),
        TimeEntry(  # cross-tenant row — invisible in the BW context
            tenant_id=tenant2.id, source="manual",
            start_at=datetime(2026, 6, 2, 9, 0, 0),
            description="tingang row",
        ),
    ]
    s.add_all(entries)
    s.commit()

    yield SimpleNamespace(
        session=s, engine=engine, tenant=tenant, users=users, batches=batches,
        parties=SimpleNamespace(rian=p_rian, adi=p_adi, gary=p_gary),
    )
    s.close()
    engine.dispose()


def fake_request(username: str, cookies: dict | None = None):
    return SimpleNamespace(
        state=SimpleNamespace(identity={"username": username, "email": ""}),
        cookies=cookies or {},
    )


def actor_for(graph, username: str, cookies: dict | None = None):
    return resolve_actor(fake_request(username, cookies), graph.session)
