# -*- coding: utf-8 -*-
"""Regression: all 12 state enum values are reachable via fixtures or paths.

Mapping table: each state → which fixture/path can produce it.
This verifies 100% state coverage across the gate system.
"""
from __future__ import annotations

import json
from pathlib import Path
from typing import Dict, List

import pytest

from utils.callback_registration import (
    ALL_STATES,
    ANU_KEY,
    STATE_AUTHORITATIVE_CALLBACK_COLLECTOR_PROCESSED,
    STATE_CALLBACK_MISSING,
    STATE_CALLBACK_PROMPT_TOO_LARGE,
    STATE_CRON_LIST_AUTODELETED_FIRED,
    STATE_DISPATCH_SUBMITTED_UNVERIFIED,
    STATE_NON_AUTHORITATIVE_SELF_COLLECTOR,
    STATE_OWNER_KEY_MISMATCH,
    STATE_OWNER_KEY_VERIFIED,
    STATE_REGISTRATION_HELPER_BYPASSED,
    STATE_RESULT_ARTIFACT_SELF_ATTESTED,
    STATE_SCHEDULE_HISTORY_PENDING,
    STATE_SOURCE_CROSS_CHECK_PARTIAL,
    register_callback,
    verify_actual_owner,
)
from utils.callback_authority_validator import validate_authority
from utils.callback_source_cross_checker import cross_check_sources

FIXTURE_DIR = Path(__file__).parent.parent.parent / "fixtures" / "callback_authority_gate"
EXECUTOR_KEY = "c38fb9955616e24d"


# ── State reachability mapping ─────────────────────────────────────────────────
STATE_REACHABILITY: Dict[str, str] = {
    STATE_AUTHORITATIVE_CALLBACK_COLLECTOR_PROCESSED:
        "validate_authority(ANU==ANU) or via authority_marker in verify_actual_owner",
    STATE_NON_AUTHORITATIVE_SELF_COLLECTOR:
        "fixture_01, fixture_03 via validate_authority(actual==executor)",
    STATE_CALLBACK_MISSING:
        "fixture_05 via cross_check_sources(all absent + cron_list=False)",
    STATE_CALLBACK_PROMPT_TOO_LARGE:
        "register_callback with prompt > 3900 bytes",
    STATE_DISPATCH_SUBMITTED_UNVERIFIED:
        "fixture_07/08 via register_callback(dispatch_path or direct_cron_path + ANU owner)",
    STATE_OWNER_KEY_MISMATCH:
        "fixture_03 via validate_authority(envelope=ANU, actual=self-key)",
    STATE_OWNER_KEY_VERIFIED:
        "fixture_02/07/08 via verify_actual_owner(observed=ANU) or cross_check_sources(all 4 present)",
    STATE_REGISTRATION_HELPER_BYPASSED:
        "fixture_06 via register_callback(dispatch_path=False, direct_cron_path=False)",
    STATE_SCHEDULE_HISTORY_PENDING:
        "cross_check_sources(schedule_history with pending status)",
    STATE_CRON_LIST_AUTODELETED_FIRED:
        "fixture_04 via cross_check_sources(cron_list=False + schedule_history present)",
    STATE_RESULT_ARTIFACT_SELF_ATTESTED:
        "cross_check_sources(result_artifact only, no schedule_history/cron_history)",
    STATE_SOURCE_CROSS_CHECK_PARTIAL:
        "cross_check_sources(partial sources)",
}


class TestAllStatesDefinedInModule:
    """ALL_STATES must contain exactly 12 states."""

    def test_all_states_count(self):
        assert len(ALL_STATES) == 12, (
            f"Expected 12 states in ALL_STATES, got {len(ALL_STATES)}: {ALL_STATES}"
        )

    def test_all_states_match_constants(self):
        expected = {
            STATE_AUTHORITATIVE_CALLBACK_COLLECTOR_PROCESSED,
            STATE_NON_AUTHORITATIVE_SELF_COLLECTOR,
            STATE_CALLBACK_MISSING,
            STATE_CALLBACK_PROMPT_TOO_LARGE,
            STATE_DISPATCH_SUBMITTED_UNVERIFIED,
            STATE_OWNER_KEY_MISMATCH,
            STATE_OWNER_KEY_VERIFIED,
            STATE_REGISTRATION_HELPER_BYPASSED,
            STATE_SCHEDULE_HISTORY_PENDING,
            STATE_CRON_LIST_AUTODELETED_FIRED,
            STATE_RESULT_ARTIFACT_SELF_ATTESTED,
            STATE_SOURCE_CROSS_CHECK_PARTIAL,
        }
        assert set(ALL_STATES) == expected


class TestStateReachabilityMapping:
    """Each state can be reached via a specific fixture or code path."""

    def test_mapping_covers_all_12_states(self):
        assert set(STATE_REACHABILITY.keys()) == set(ALL_STATES), (
            f"Reachability map doesn't cover all states.\n"
            f"Missing: {set(ALL_STATES) - set(STATE_REACHABILITY.keys())}"
        )

    @pytest.mark.parametrize("state", ALL_STATES)
    def test_each_state_documented(self, state: str):
        assert state in STATE_REACHABILITY, (
            f"State {state!r} has no reachability documentation"
        )


class TestStateActualReachability:
    """Concrete code paths that produce each state."""

    def test_state_registration_helper_bypassed(self):
        rr = register_callback(
            kind="normal", task_id="t", executor_key=EXECUTOR_KEY,
            owner_key=ANU_KEY, chat_id="c", prompt="p", at="10m",
            dispatch_path=False, direct_cron_path=False,
        )
        assert rr.state == STATE_REGISTRATION_HELPER_BYPASSED

    def test_state_dispatch_submitted_unverified(self):
        rr = register_callback(
            kind="normal", task_id="t2", executor_key=EXECUTOR_KEY,
            owner_key=ANU_KEY, chat_id="c", prompt="task_id=t2\nowner_key=anu\n",
            at="10m", dispatch_path=True, direct_cron_path=False,
            require_envelope=False,
        )
        assert rr.state == STATE_DISPATCH_SUBMITTED_UNVERIFIED

    def test_state_owner_key_verified(self):
        rr = register_callback(
            kind="normal", task_id="t3", executor_key=EXECUTOR_KEY,
            owner_key=ANU_KEY, chat_id="c", prompt="p", at="10m",
            dispatch_path=True, direct_cron_path=False, require_envelope=False,
        )
        verified = verify_actual_owner(
            registration_result=rr,
            observed_owner_key=ANU_KEY, observed_chat_id="c", observed_role="ANU",
        )
        assert verified.state == STATE_OWNER_KEY_VERIFIED

    def test_state_callback_prompt_too_large(self):
        prompt = "x" * 4000  # > 3900 bytes
        rr = register_callback(
            kind="normal", task_id="t4", executor_key=EXECUTOR_KEY,
            owner_key=ANU_KEY, chat_id="c", prompt=prompt, at="10m",
            dispatch_path=True, direct_cron_path=False, require_envelope=False,
        )
        assert rr.state == STATE_CALLBACK_PROMPT_TOO_LARGE

    def test_state_non_authoritative_self_collector(self):
        verdict = validate_authority(
            envelope_collector_key=EXECUTOR_KEY,
            actual_owner_key=EXECUTOR_KEY,
            executor_key=EXECUTOR_KEY,
        )
        assert verdict.state == STATE_NON_AUTHORITATIVE_SELF_COLLECTOR

    def test_state_owner_key_mismatch(self):
        verdict = validate_authority(
            envelope_collector_key=ANU_KEY,
            actual_owner_key="non-anu-key",
            executor_key=EXECUTOR_KEY,
        )
        assert verdict.state == STATE_OWNER_KEY_MISMATCH

    def test_state_callback_missing(self):
        r = cross_check_sources(
            cron_id="X", schedule_history_records=[], cron_history_records={},
            envelope=None, result_artifact=None, cron_list_present=False,
        )
        assert r.state == STATE_CALLBACK_MISSING

    def test_state_cron_list_autodeleted_fired(self):
        r = cross_check_sources(
            cron_id="X",
            schedule_history_records=[{"status": "fired"}],
            cron_history_records={},
            envelope=None, result_artifact=None, cron_list_present=False,
        )
        assert r.state == STATE_CRON_LIST_AUTODELETED_FIRED

    def test_state_schedule_history_pending(self):
        r = cross_check_sources(
            cron_id="X",
            schedule_history_records=[{"status": "pending"}],
            cron_history_records={},
            envelope=None, result_artifact=None, cron_list_present=False,
        )
        assert r.state == STATE_SCHEDULE_HISTORY_PENDING

    def test_state_result_artifact_self_attested(self):
        r = cross_check_sources(
            cron_id="X", schedule_history_records=[],
            cron_history_records={ANU_KEY: [], EXECUTOR_KEY: []},
            envelope={"collector_key": ANU_KEY},
            result_artifact={"schedule_id": "X"},
            cron_list_present=None,
        )
        assert r.state == STATE_RESULT_ARTIFACT_SELF_ATTESTED

    def test_state_source_cross_check_partial(self):
        r = cross_check_sources(
            cron_id="X", schedule_history_records=[],
            cron_history_records={ANU_KEY: [{"x": 1}]},
            envelope=None, result_artifact=None, cron_list_present=None,
        )
        assert r.state == STATE_SOURCE_CROSS_CHECK_PARTIAL

    def test_state_authoritative_callback_collector_processed(self):
        """authority_marker field contains this value when OWNER_KEY_VERIFIED."""
        from utils.callback_authority_validator import MARKER_AUTHORITATIVE
        assert MARKER_AUTHORITATIVE == STATE_AUTHORITATIVE_CALLBACK_COLLECTOR_PROCESSED
