#!/usr/bin/env python3
import json
import re
import sys


def parse_ls_remote_lines(lines):
    refs = {}
    for line in lines:
        parts = line.split()
        if len(parts) == 2:
            refs[parts[1]] = parts[0]
    return refs


def parse_github_hooks_response(ok, status, body):
    if ok is not True:
        return {"ok": False, "status": status, "hooks": [], "error": f"github-hooks-http-{status or 'unknown'}"}
    try:
        payload = json.loads(body or "[]")
    except (TypeError, json.JSONDecodeError):
        return {"ok": False, "status": status, "hooks": [], "error": "github-hooks-response-invalid-json"}
    if not isinstance(payload, list):
        return {"ok": False, "status": status, "hooks": [], "error": "github-hooks-response-not-list"}
    if any(not isinstance(item, dict) for item in payload):
        return {"ok": False, "status": status, "hooks": [], "error": "github-hooks-item-not-object"}
    return {"ok": True, "status": status, "hooks": payload, "error": None}


def github_hook_url(item):
    if not isinstance(item, dict):
        return ""
    config = item.get("config")
    if isinstance(config, str):
        return config
    if isinstance(config, dict) and isinstance(config.get("url"), str):
        return config["url"]
    return ""


def select_committed_head_record(repo_key, github_head, records):
    candidates = []
    for record in records:
        if not isinstance(record, dict) or record.get("repo") != repo_key or record.get("state") != "committed":
            continue
        result = record.get("result") if isinstance(record.get("result"), dict) else {}
        if record.get("requestedCommit") != github_head or result.get("sourceCommit") != github_head:
            continue
        if result.get("authorityCommit") not in (None, github_head):
            continue
        candidates.append(record)
    return max(candidates, key=lambda item: (int(item.get("acceptedSequence") or 0), str(item.get("committedAt") or "")), default=None)


def select_target_delivery(deliveries, repository, ref, requested_commit=None, delivery_id=None):
    candidates = []
    for delivery in deliveries:
        if not isinstance(delivery, dict):
            continue
        if delivery.get("repository") != repository or delivery.get("ref") != ref:
            continue
        if requested_commit is not None and delivery.get("requestedCommit") != requested_commit:
            continue
        if delivery_id is not None and _delivery_id(delivery) != str(delivery_id):
            continue
        candidates.append(delivery)
    return max(candidates, key=lambda item: (str(item.get("deliveredAt") or ""), str(item.get("id") or "")), default=None)


def select_snapshot(branch_commit, snapshot_prefix, refs):
    if not branch_commit:
        return {
            "expectedSnapshotRef": None,
            "snapshotRef": None,
            "snapshotCommit": None,
            "sourceBundleReady": False,
        }
    expected_ref = f"{snapshot_prefix.rstrip('/')}/{branch_commit}"
    snapshot_commit = refs.get(expected_ref)
    return {
        "expectedSnapshotRef": expected_ref,
        "snapshotRef": expected_ref if snapshot_commit else None,
        "snapshotCommit": snapshot_commit,
        "sourceBundleReady": snapshot_commit == branch_commit,
    }


def evaluate_repository(repo, hook, head, mirror, bridge_events, inbox_records=None, journal=None):
    inbox_records = inbox_records or []
    github_head = head.get("sha")
    branch_commit = mirror.get("branchCommit")
    snapshot_commit = mirror.get("snapshotCommit")
    expected_snapshot_ref = f"{repo['snapshot']['prefix'].rstrip('/')}/{github_head}" if github_head else None
    snapshot_ref = mirror.get("snapshotRef")
    latest_delivery = hook.get("latest")
    latest_push_delivery = hook.get("latestPush")
    selected_push_delivery = hook.get("selectedPush")
    delivery_id = _delivery_id(selected_push_delivery)
    delivery_repository = selected_push_delivery.get("repository") if isinstance(selected_push_delivery, dict) else None
    delivery_ref = selected_push_delivery.get("ref") if isinstance(selected_push_delivery, dict) else None
    delivery_requested_commit = selected_push_delivery.get("requestedCommit") if isinstance(selected_push_delivery, dict) else None
    delivery_scope_matches = bool(
        delivery_repository == repo["upstream"]["repository"]
        and delivery_ref == f"refs/heads/{repo['upstream']['branch']}"
        and isinstance(delivery_requested_commit, str)
        and re.fullmatch(r"[0-9a-f]{40,64}", delivery_requested_commit)
    )
    delivery_accepted = bool(
        isinstance(selected_push_delivery, dict)
        and delivery_scope_matches
        and selected_push_delivery.get("statusCode") in (200, 202)
    )
    correlated_inbox_records = [
        record for record in inbox_records
        if record.get("repo") == repo["key"]
        and record.get("deliveryId") == delivery_id
    ]
    inbox_record = correlated_inbox_records[-1] if correlated_inbox_records else None
    pre_durable_bootstrap = _is_pre_durable_bootstrap(selected_push_delivery, inbox_record, journal)
    inbox_state = inbox_record.get("state") if inbox_record else ("pre-durable-bootstrap" if pre_durable_bootstrap else None)
    inbox_result = inbox_record.get("result") if isinstance(inbox_record, dict) and isinstance(inbox_record.get("result"), dict) else {}
    correlated = [
        event for event in bridge_events
        if event.get("repo") == repo["key"]
        and event.get("deliveryId") == delivery_id
        and event.get("event") == "github-to-gitea-sync"
        and event.get("terminal") is True
    ]
    correlated_event = correlated[-1] if correlated else None
    branch_matches_github = bool(github_head and branch_commit == github_head)
    snapshot_matches_github = bool(
        github_head
        and snapshot_commit == github_head
        and snapshot_ref == expected_snapshot_ref
    )
    authority_matches = branch_matches_github and snapshot_matches_github
    inbox_correlated = inbox_record is not None
    inbox_committed = bool(
        inbox_record
        and inbox_state == "committed"
        and inbox_record.get("requestedCommit") == delivery_requested_commit
        and inbox_result.get("sourceCommit") == delivery_requested_commit
        and (
            delivery_requested_commit == github_head
            or (
                inbox_result.get("disposition") == "superseded-with-immutable-snapshot"
                and inbox_result.get("authorityCommit") == github_head
            )
        )
    )
    durable_proof_acceptable = inbox_committed or (pre_durable_bootstrap and delivery_requested_commit == github_head)
    stale = not (
        authority_matches
        and delivery_accepted
        and durable_proof_acceptable
    )
    stale_reason = _stale_reason(
        hook,
        head,
        delivery_accepted,
        delivery_scope_matches,
        inbox_record,
        pre_durable_bootstrap,
        github_head,
        branch_matches_github,
        snapshot_matches_github,
    ) if stale else None
    error = _error(hook, head, stale_reason)
    return {
        "key": repo["key"],
        "repository": repo["upstream"]["repository"],
        "branch": repo["upstream"]["branch"],
        "hookId": hook.get("hookId"),
        "hookReady": hook.get("hookReady") is True,
        "active": hook.get("active"),
        "status": hook.get("status"),
        "githubHead": github_head,
        "branchCommit": branch_commit,
        "snapshotRef": snapshot_ref,
        "expectedSnapshotRef": expected_snapshot_ref,
        "snapshotCommit": snapshot_commit,
        "branchMatchesGitHub": branch_matches_github,
        "snapshotMatchesGitHub": snapshot_matches_github,
        "authorityMatches": authority_matches,
        "latestDelivery": latest_delivery,
        "latestPushDelivery": latest_push_delivery,
        "selectedPushDelivery": selected_push_delivery,
        "deliverySelectionReason": hook.get("deliverySelectionReason") or "latest-push-delivery",
        "matchingHookCount": hook.get("matchingHookCount"),
        "matchingHookIds": hook.get("matchingHookIds") or [],
        "hookTopologyReason": hook.get("hookTopologyReason"),
        "hookTopology": hook.get("hookTopology") if isinstance(hook.get("hookTopology"), dict) else {},
        "deliveryId": delivery_id,
        "deliveryRepository": delivery_repository,
        "deliveryRef": delivery_ref,
        "deliveryRequestedCommit": delivery_requested_commit,
        "deliveryScopeMatches": delivery_scope_matches,
        "correlatedBridgeEvent": correlated_event,
        "durableInboxRecord": inbox_record,
        "durableInboxState": inbox_state,
        "durableInboxCommitted": inbox_committed,
        "preDurableBootstrap": pre_durable_bootstrap,
        "deliveryAccepted": delivery_accepted,
        "bridgeEventStale": stale,
        "staleReason": stale_reason,
        "error": error,
        "valuesPrinted": False,
    }


def _delivery_id(delivery):
    if not isinstance(delivery, dict):
        return ""
    return str(delivery.get("deliveryId") or delivery.get("guid") or delivery.get("id") or "")


def _stale_reason(hook, head, delivery_accepted, delivery_scope_matches, inbox_record, pre_durable_bootstrap, github_head, branch_matches, snapshot_matches):
    if hook.get("hookReady") is not True:
        return "github-hook-not-ready"
    if head.get("ok") is not True or not github_head:
        return "github-head-unavailable"
    if not delivery_scope_matches:
        return "target-branch-delivery-scope-mismatch-or-missing"
    if not delivery_accepted:
        return "target-branch-delivery-failed"
    if not inbox_record and not pre_durable_bootstrap:
        return "no-correlated-durable-inbox-record"
    if not pre_durable_bootstrap:
        inbox_state = inbox_record.get("state")
        if inbox_state != "committed":
            return f"durable-inbox-{inbox_state or 'unknown'}-not-committed"
        result = inbox_record.get("result") if isinstance(inbox_record.get("result"), dict) else {}
        delivery_requested_commit = (hook.get("selectedPush") or {}).get("requestedCommit")
        inbox_proves_head = (
            inbox_record.get("requestedCommit") == delivery_requested_commit
            and result.get("sourceCommit") == delivery_requested_commit
            and (
                delivery_requested_commit == github_head
            or (
                result.get("disposition") == "superseded-with-immutable-snapshot"
                and result.get("authorityCommit") == github_head
            )
            )
        )
        if not inbox_proves_head:
            return "correlated-inbox-proof-head-mismatch"
    if not branch_matches:
        return "gitea-branch-behind-github"
    if not snapshot_matches:
        return "gitea-snapshot-behind-github"
    return "authority-proof-incomplete"


def _is_pre_durable_bootstrap(delivery, inbox_record, journal):
    if inbox_record is not None or not isinstance(delivery, dict) or not isinstance(journal, dict):
        return False
    delivered_at = delivery.get("deliveredAt")
    created_at = journal.get("createdAt")
    if not isinstance(delivered_at, str) or not isinstance(created_at, str):
        return False
    try:
        from datetime import datetime
        return datetime.fromisoformat(delivered_at.replace("Z", "+00:00")) < datetime.fromisoformat(created_at.replace("Z", "+00:00"))
    except ValueError:
        return False


def _error(hook, head, stale_reason):
    if hook.get("error"):
        return hook.get("error")
    if head.get("error"):
        return head.get("error")
    if stale_reason:
        return f"source authority stale: {stale_reason}"
    return None


def main():
    payload = json.load(sys.stdin)
    action = payload.get("action")
    if action == "parse-ls-remote":
        result = parse_ls_remote_lines(str(payload.get("output") or "").splitlines())
    elif action == "parse-github-hooks-response":
        result = parse_github_hooks_response(payload.get("ok"), payload.get("status"), payload.get("body"))
    elif action == "github-hook-url":
        result = github_hook_url(payload.get("hook"))
    elif action == "select-committed-head-record":
        result = select_committed_head_record(payload.get("repoKey"), payload.get("githubHead"), payload.get("records", []))
    elif action == "select-target-delivery":
        result = select_target_delivery(payload.get("deliveries", []), payload.get("repository"), payload.get("ref"), payload.get("requestedCommit"), payload.get("deliveryId"))
    elif action == "select-snapshot":
        result = select_snapshot(payload.get("branchCommit"), payload["snapshotPrefix"], payload.get("refs", {}))
    elif action == "evaluate-repository":
        result = evaluate_repository(payload["repo"], payload["hook"], payload["head"], payload.get("mirror", {}), payload.get("bridgeEvents", []), payload.get("inboxRecords", []), payload.get("journal"))
    else:
        raise SystemExit("unsupported action")
    print(json.dumps(result, ensure_ascii=False, indent=2))


if __name__ == "__main__":
    main()
