#!/usr/bin/env python3
"""Find candidate tickets across the four required pre-create states."""
from __future__ import annotations

import argparse
import json
from pathlib import Path

REQUIRED_STATES = ("New", "Ready", "Active", "Blocked")


def main() -> int:
    parser = argparse.ArgumentParser()
    parser.add_argument("ticket_file", type=Path)
    parser.add_argument("--terms", required=True, help="comma-separated search terms")
    parser.add_argument(
        "--after-readback",
        type=Path,
        help="optional post-write export used to verify the canonical and duplicate tickets",
    )
    args = parser.parse_args()
    data = json.loads(args.ticket_file.read_text(encoding="utf-8"))
    target = data.get("target", {})
    request = data.get("request", {})
    if any(not target.get(field) for field in ("lane", "project", "queue")):
        raise SystemExit("ticket export must identify the target lane, project, and queue")
    if any(not request.get(field) for field in ("requested_outcome", "rationale")):
        raise SystemExit("ticket export must identify the requested outcome and rationale")
    if tuple(data.get("required_states", ())) != REQUIRED_STATES:
        raise SystemExit("ticket export must include New, Ready, Active, and Blocked")

    terms = tuple(term.strip().casefold() for term in args.terms.split(",") if term.strip())
    if len(terms) < 2:
        raise SystemExit("use at least two symptom, component, or outcome terms")

    candidates = []
    for ticket in data["tickets"]:
        if ticket["state"] not in REQUIRED_STATES:
            continue
        title = ticket["title"].casefold()
        description = ticket["description"].casefold()
        matches = [term for term in terms if term in title or term in description]
        if matches:
            candidates.append((ticket, matches, not any(term in title for term in terms)))

    readback = None
    if args.after_readback is not None:
        after = json.loads(args.after_readback.read_text(encoding="utf-8"))
        if after.get("target") != target or after.get("request") != request:
            raise SystemExit("post-write readback must preserve the exact target and request")
        readback = after.get("readback", {})
        canonical_id = readback.get("canonical_ticket_id")
        duplicate_id = readback.get("duplicate_ticket_id")
        incident_evidence = readback.get("incident_evidence")
        after_tickets = {ticket["id"]: ticket for ticket in after.get("tickets", [])}
        canonical = after_tickets.get(canonical_id, {})
        duplicate = after_tickets.get(duplicate_id, {})
        if not canonical_id or not duplicate_id or canonical_id == duplicate_id:
            raise SystemExit("post-write readback must identify distinct canonical and duplicate tickets")
        if (
            not incident_evidence
            or canonical.get("state") != "Active"
            or incident_evidence not in canonical.get("evidence", [])
            or canonical.get("dispatch_authority") is not True
        ):
            raise SystemExit(
                "post-write canonical ticket must remain Active, retain dispatch authority, and contain the new incident evidence"
            )
        if (
            duplicate.get("state") != "Closed"
            or duplicate.get("resolution") != "Duplicate"
            or duplicate.get("duplicate_of") != canonical_id
            or duplicate.get("dispatch_authority") is not False
        ):
            raise SystemExit(
                "post-write duplicate ticket must be closed, marked Duplicate, linked to the canonical ticket, and stripped of dispatch authority"
            )

    print(
        f"target_lane={target['lane']} project={target['project']} "
        f"queue={target['queue']}"
    )
    print(f"requested_outcome={request['requested_outcome']}")
    print(f"request_rationale={request['rationale']}")
    print("states=" + ",".join(REQUIRED_STATES))
    for ticket, matches, body_only in candidates:
        print(
            f"candidate={ticket['id']} state={ticket['state']} "
            f"matches={','.join(matches)} body_only={str(body_only).lower()}"
        )
    print(f"candidate_count={len(candidates)} read_required={len(candidates)}")
    if readback is not None:
        canonical = after_tickets[readback["canonical_ticket_id"]]
        duplicate = after_tickets[readback["duplicate_ticket_id"]]
        print(
            f"readback={canonical['id']} state={canonical['state']} "
            "incident_evidence=true dispatch_authority=true"
        )
        print(
            f"readback={duplicate['id']} state={duplicate['state']} "
            f"resolution={duplicate['resolution']} duplicate_of={duplicate['duplicate_of']} "
            "dispatch_authority=false"
        )
        print(
            f"readback_result=PASS canonical_ticket={canonical['id']} "
            f"duplicate_ticket={duplicate['id']}"
        )
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
