#!/usr/bin/env python3
"""Original LockedIn Labs Identity 101 lab. Python 3.11+, standard library.

Real in-memory SQLite reads; fictional records and trusted-context fixtures.
No login, credential verification, network, model, cloud account or disk writes.
This is an authorization teaching example, not an authentication implementation.
"""
import argparse
from contextlib import closing
from dataclasses import asdict, dataclass
import json
import sqlite3


@dataclass(frozen=True)
class Principal:
    subject: str
    tenant: str


def prepare_database():
    db = sqlite3.connect(":memory:")
    db.row_factory = sqlite3.Row
    db.executescript("""
        CREATE TABLE documents (
            tenant TEXT NOT NULL, id TEXT NOT NULL, text TEXT NOT NULL,
            PRIMARY KEY (tenant, id)
        );
        CREATE TABLE grants (
            subject TEXT NOT NULL, tenant TEXT NOT NULL,
            document_id TEXT NOT NULL, action TEXT NOT NULL,
            PRIMARY KEY (subject, tenant, document_id, action)
        );
    """)
    db.executemany("INSERT INTO documents VALUES (?, ?, ?)", [
        ("north", "P-7", "NORTH ONLY: Pump-7 uses checklist N."),
        ("south", "P-7", "SOUTH ONLY: Pump-7 uses checklist S."),
        ("north", "P-8", "RESTRICTED: internal incident notes."),
    ])
    # U-7 has access in both organizations, but works in one trusted scope at a time.
    db.executemany("INSERT INTO grants VALUES (?, ?, ?, ?)", [
        ("U-7", "north", "P-7", "read"),
        ("U-7", "south", "P-7", "read"),
    ])
    return db


def read_document(db, principal, request):
    """principal comes from the trusted host, never from request/model arguments.

    The real identity-verification step is intentionally outside this local lab.
    Trace labels are learner evidence, not a production error/telemetry contract.
    """
    trace = []

    def result(state, response, queried=False, row=None):
        return {"state": state, "trace": trace, "query_executed": queried,
                "rows_returned": int(row is not None), "response": response}

    if principal is None:
        trace.append("No verified caller context; do not query documents.")
        return result("authentication_required", {"error": "sign_in_required"})
    trace.append("Use trusted caller and active organization.")
    if not isinstance(request, dict) or set(request) - {"document_id", "tenant"}:
        return result("invalid_request", {"error": "invalid_request"})
    document_id = request.get("document_id")
    if not isinstance(document_id, str) or not 1 <= len(document_id) <= 64:
        return result("invalid_request", {"error": "invalid_request"})
    if "tenant" in request and request["tenant"] != principal.tenant:
        trace.append("Requested organization differs from trusted scope.")
        return result("scope_refused", {"error": "not_available"})

    # Read the body only through this parameterized, permission-scoped query.
    # The read operation is fixed by this function, not selected by the model.
    row = db.execute("""
        SELECT d.id, d.text FROM documents AS d
        JOIN grants AS g ON g.tenant = d.tenant AND g.document_id = d.id
        WHERE d.tenant = ? AND d.id = ? AND g.subject = ? AND g.action = 'read'
    """, (principal.tenant, document_id, principal.subject)).fetchone()
    trace.append("Query matches active organization, document, caller and read grant.")
    if row is None:
        trace.append("No permitted row; return no document content.")
        return result("not_available", {"error": "not_available"}, queried=True)
    trace.append("Return only the permitted document fields.")
    return result("allowed", dict(row), queried=True, row=row)


CASES = ("allowed", "anonymous", "claim-tenant", "restricted", "revoked")


def run_case(case):
    if case not in CASES:
        raise ValueError("unknown_case")
    principal = None if case == "anonymous" else Principal("U-7", "north")
    request = {"document_id": "P-7"}
    if case == "claim-tenant":
        request["tenant"] = "south"  # Experiment A: change only this value to north.
    if case == "restricted":
        request["document_id"] = "P-8"  # Experiment B: change only this value to P-7.
    with closing(prepare_database()) as db:
        observations = [{"when": "first read", **read_document(db, principal, request)}]
        if case == "revoked":
            db.execute("DELETE FROM grants WHERE subject = ? AND tenant = ? AND document_id = ? AND action = 'read'",
                       (principal.subject, principal.tenant, request["document_id"]))
            observations.append({"when": "after read grant removed", **read_document(db, principal, request)})
    return {"case": case, "trusted_context_fixture": asdict(principal) if principal else None,
            "untrusted_request": request, "observations": observations,
            "boundary": "Identity verification is assumed by the fixture. SQL authorization is actually executed. No model receives data."}


if __name__ == "__main__":
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("case", choices=CASES)
    print(json.dumps(run_case(parser.parse_args().case), indent=2))
