"""Independent synthetic unequal-time operator-block reference for AP1-R3.

This module intentionally does not import the AP1-R3 preflight implementation.
It computes the same free-oscillator composite-operator commutator in two
independent ways: directly in a truncated Fock basis and through the Gaussian
Wightman/Wick identity.  All checks are structural canaries; none is a physical
or renormalized Apeiron response kernel.
"""
from __future__ import annotations

from hashlib import sha256
import json
from math import atan
from pathlib import Path

import numpy as np


SOURCE_LABELS = ("metric_stress", "sigma_portal", "theta_portal")
SYNTHETIC_SOURCE_WEIGHTS = np.array((1.0, -0.5, 0.25), dtype=float)
SYNTHETIC_IDENTITY_MATRIX = np.array(((0.5, 1.0, 0.0), (-0.25, 0.0, 1.0)), dtype=float)
TIME_NODE_BUDGETS = (17, 33, 65)
MOMENTUM_NODE_BUDGETS = (8, 16, 32)
MEMORY_FRACTIONS = (0.5, 0.75, 1.0)
FOCK_VARIANTS = (4, 6, 8)


class UnequalTimeReferenceError(RuntimeError):
    """A synthetic reference invariant failed or a physical claim leaked in."""


def file_sha256(path: Path) -> str:
    digest = sha256()
    with path.open("rb") as stream:
        for block in iter(lambda: stream.read(1024 * 1024), b""):
            digest.update(block)
    return digest.hexdigest()


def validate_time_grid(times: np.ndarray) -> np.ndarray:
    values = np.asarray(times, dtype=float)
    if values.ndim != 1 or values.size < 2 or not np.all(np.isfinite(values)):
        raise ValueError("finite one-dimensional time grid with at least two nodes required")
    if np.any(np.diff(values) <= 0.0):
        raise ValueError("time grid must be strictly increasing")
    return values


def retarded_mask(times: np.ndarray) -> np.ndarray:
    values = validate_time_grid(times)
    return values[None, :] <= values[:, None]


def annihilation_operator(dimension: int) -> np.ndarray:
    if not isinstance(dimension, int) or dimension < 3:
        raise ValueError("Fock dimension must be an integer of at least three")
    operator = np.zeros((dimension, dimension), dtype=np.complex128)
    for level in range(1, dimension):
        operator[level - 1, level] = np.sqrt(float(level))
    return operator


def coordinate_operator(time: float, omega: float, dimension: int) -> np.ndarray:
    if not np.isfinite(time) or not np.isfinite(omega) or omega <= 0.0:
        raise ValueError("finite time and positive finite frequency required")
    lowering = annihilation_operator(dimension)
    raising = lowering.T.conj()
    return (
        lowering * np.exp(-1j * omega * time)
        + raising * np.exp(1j * omega * time)
    ) / np.sqrt(2.0 * omega)


def direct_fock_retarded_chi2(times: np.ndarray, omega: float, dimension: int) -> np.ndarray:
    """Compute -i Theta(t-t') <0|[chi^2(t),chi^2(t')]|0> directly."""

    values = validate_time_grid(times)
    mask = retarded_mask(values)
    # Matrix multiplication, not elementwise squaring, is required here.
    squared = [coordinate_operator(float(t), omega, dimension) @ coordinate_operator(float(t), omega, dimension) for t in values]
    vacuum = np.zeros(dimension, dtype=np.complex128)
    vacuum[0] = 1.0
    response = np.zeros(mask.shape, dtype=np.complex128)
    for row in range(values.size):
        for column in range(row + 1):
            commutator = squared[row] @ squared[column] - squared[column] @ squared[row]
            expectation = np.vdot(vacuum, commutator @ vacuum)
            response[row, column] = -1j * expectation
    return response


def wick_retarded_chi2(times: np.ndarray, omega: float) -> np.ndarray:
    """Gaussian/Wick route for the same normalized chi^2 commutator."""

    values = validate_time_grid(times)
    if not np.isfinite(omega) or omega <= 0.0:
        raise ValueError("positive finite frequency required")
    delta = values[:, None] - values[None, :]
    wightman = np.exp(-1j * omega * delta) / (2.0 * omega)
    return np.where(retarded_mask(values), 4.0 * np.imag(wightman * wightman), 0.0)


def assemble_source_block(base_kernel: np.ndarray, weights: np.ndarray = SYNTHETIC_SOURCE_WEIGHTS) -> np.ndarray:
    base = np.asarray(base_kernel)
    source_weights = np.asarray(weights, dtype=float)
    if base.ndim != 2 or base.shape[0] != base.shape[1] or not np.all(np.isfinite(base)):
        raise ValueError("finite square unequal-time base kernel required")
    if source_weights.shape != (len(SOURCE_LABELS),) or not np.all(np.isfinite(source_weights)):
        raise ValueError("one finite synthetic weight per registered source required")
    return np.einsum("a,b,ij->abij", source_weights, source_weights, base)


def oscillator_wronskian(times: np.ndarray, omega: float) -> np.ndarray:
    values = validate_time_grid(times)
    if not np.isfinite(omega) or omega <= 0.0:
        raise ValueError("positive finite frequency required")
    mode = np.exp(-1j * omega * values) / np.sqrt(2.0 * omega)
    derivative = -1j * omega * mode
    return mode * derivative.conj() - mode.conj() * derivative


def momentum_quadrature_canary(nodes: int) -> float:
    """Smooth analytic quadrature canary; unrelated to a physical loop integral."""

    if not isinstance(nodes, int) or nodes < 2:
        raise ValueError("at least two momentum nodes required")
    abscissa, weights = np.polynomial.legendre.leggauss(nodes)
    momentum = 0.5 * (abscissa + 1.0)
    integrand = 1.0 / (1.0 + 16.0 * momentum * momentum)
    return float(0.5 * np.dot(weights, integrand))


def _reference_error_budget(omega: float) -> float:
    scale = max(1.0, 1.0 / (omega * omega))
    return float(1024.0 * np.finfo(float).eps * scale)


def build_reference_report(
    response_spec: Path,
    a3_requirements: Path,
    g22_checkpoint: Path,
    structural_preflight: Path,
    local_manifest: Path,
    *,
    omega: float = 1.7,
) -> dict:
    if not np.isfinite(omega) or omega <= 0.0:
        raise ValueError("positive finite frequency required")

    g22 = json.loads(g22_checkpoint.read_text(encoding="utf-8"))
    preflight = json.loads(structural_preflight.read_text(encoding="utf-8"))
    manifest = json.loads(local_manifest.read_text(encoding="utf-8"))
    if g22.get("classification") != "G22_PASS" or g22.get("nonpass_stored_or_used_as_seed") is not False:
        raise UnequalTimeReferenceError("frozen G22 PASS prerequisite rejected")
    if preflight.get("classification") != "R3_STRUCTURAL_PREFLIGHT_PASS_PHYSICAL_KERNEL_NOT_COMPUTED":
        raise UnequalTimeReferenceError("structural R3 preflight prerequisite rejected")
    if manifest.get("validation", {}).get("status") != "PASS_FAIL_CLOSED":
        raise UnequalTimeReferenceError("local variation manifest is not validated")
    if manifest.get("physical_kernel_ready") is not False:
        raise UnequalTimeReferenceError("local manifest improperly releases a physical run")

    tolerance = _reference_error_budget(omega)
    master_times = np.linspace(0.0, 2.0, 65)
    reference_times = master_times[::4]
    wick_reference = wick_retarded_chi2(reference_times, omega)

    fock_responses = {
        dimension: direct_fock_retarded_chi2(reference_times, omega, dimension)
        for dimension in FOCK_VARIANTS
    }
    direct_wick_errors = {
        str(dimension): float(np.max(np.abs(response - wick_reference)))
        for dimension, response in fock_responses.items()
    }
    basis_variant_error = float(
        max(
            np.max(np.abs(fock_responses[left] - fock_responses[right]))
            for left, right in zip(FOCK_VARIANTS[:-1], FOCK_VARIANTS[1:])
        )
    )

    direct = fock_responses[max(FOCK_VARIANTS)]
    direct_reality_error = float(np.max(np.abs(np.imag(direct))))
    direct_upper_causal_error = float(np.max(np.abs(np.triu(direct, 1))))
    direct_equal_time_error = float(np.max(np.abs(np.diag(direct))))

    real_base = np.real(direct)
    source_block = assemble_source_block(real_base)
    source_reciprocity_error = float(np.max(np.abs(source_block - source_block.swapaxes(0, 1))))
    identity_residual = np.einsum("ca,abij->cbij", SYNTHETIC_IDENTITY_MATRIX, source_block)
    source_identity_error = float(np.max(np.abs(identity_residual)))

    wronskian_error = float(np.max(np.abs(oscillator_wronskian(master_times, omega) - 1j)))

    time_grid_errors: dict[str, float] = {}
    for nodes, stride in ((17, 4), (33, 2), (65, 1)):
        selected = master_times[::stride]
        independently_built = wick_retarded_chi2(selected, omega)
        restricted_master = wick_retarded_chi2(master_times, omega)[::stride, ::stride]
        time_grid_errors[str(nodes)] = float(np.max(np.abs(independently_built - restricted_master)))

    memory_prefix_errors: dict[str, float] = {}
    full_kernel = wick_retarded_chi2(master_times, omega)
    for fraction in MEMORY_FRACTIONS:
        final_index = int(round(fraction * (master_times.size - 1)))
        prefix_times = master_times[: final_index + 1]
        independently_built = wick_retarded_chi2(prefix_times, omega)
        restricted_full = full_kernel[: final_index + 1, : final_index + 1]
        memory_prefix_errors[str(fraction)] = float(np.max(np.abs(independently_built - restricted_full)))

    exact_momentum_canary = atan(4.0) / 4.0
    momentum_values = {str(nodes): momentum_quadrature_canary(nodes) for nodes in MOMENTUM_NODE_BUDGETS}
    momentum_errors = {
        key: float(abs(value - exact_momentum_canary)) for key, value in momentum_values.items()
    }
    ordered_momentum_errors = [momentum_errors[str(nodes)] for nodes in MOMENTUM_NODE_BUDGETS]

    gates = {
        "direct_Fock_matches_independent_Wick_path": max(direct_wick_errors.values()) <= tolerance,
        "three_Fock_basis_variants_agree": basis_variant_error <= tolerance,
        "retarded_support_exact_within_roundoff_budget": direct_upper_causal_error <= tolerance,
        "real_operator_response_canary": direct_reality_error <= tolerance,
        "equal_time_commutator_zero": direct_equal_time_error <= tolerance,
        "source_block_reciprocity": source_reciprocity_error <= tolerance,
        "synthetic_coupled_source_identity": source_identity_error <= tolerance,
        "oscillator_Wronskian_preserved": wronskian_error <= tolerance,
        "nested_time_grid_consistency": max(time_grid_errors.values()) <= tolerance,
        "memory_prefix_consistency": max(memory_prefix_errors.values()) <= tolerance,
        "momentum_quadrature_converges_8_16_32": (
            ordered_momentum_errors[1] < ordered_momentum_errors[0]
            and ordered_momentum_errors[2] < ordered_momentum_errors[1]
            and ordered_momentum_errors[2] <= 1.0e-12
        ),
    }
    if not all(gates.values()):
        raise UnequalTimeReferenceError(f"synthetic unequal-time reference failed closed: {gates}")

    physical_block_reason = "NOT_EXECUTED__NEW_M1_BACKGROUND_AND_PRE_FROZEN_PHYSICAL_TOLERANCES_REQUIRED"
    return {
        "schema": "apeiron-ap1-r3-synthetic-unequal-time-reference-v1.0",
        "classification": "R3_SYNTHETIC_UNEQUAL_TIME_REFERENCE_PASS_PHYSICAL_KERNEL_BLOCKED",
        "authority_sha256": {
            "response_spec": file_sha256(response_spec),
            "a3_requirements": file_sha256(a3_requirements),
            "g22_checkpoint": file_sha256(g22_checkpoint),
            "structural_preflight_snapshot": file_sha256(structural_preflight),
            "local_variation_manifest": file_sha256(local_manifest),
        },
        "independence_contract": {
            "direct_path": "finite_Fock_operator_matrix_vacuum_commutator",
            "reference_path": "analytic_Gaussian_Wightman_Wick_identity",
            "imports_existing_R3_preflight_implementation": False,
            "synthetic_only": True,
        },
        "registered_budgets": {
            "time_nodes": list(TIME_NODE_BUDGETS),
            "momentum_nodes": list(MOMENTUM_NODE_BUDGETS),
            "memory_fractions": list(MEMORY_FRACTIONS),
            "Fock_basis_variants": list(FOCK_VARIANTS),
            "reference_roundoff_budget": tolerance,
            "physical_gate_thresholds_frozen": False,
        },
        "diagnostics": {
            "oscillator_omega": omega,
            "direct_Wick_max_errors_by_Fock_dimension": direct_wick_errors,
            "basis_variant_max_error": basis_variant_error,
            "upper_causal_error": direct_upper_causal_error,
            "reality_error": direct_reality_error,
            "equal_time_error": direct_equal_time_error,
            "source_reciprocity_error": source_reciprocity_error,
            "synthetic_source_identity_error": source_identity_error,
            "Wronskian_error": wronskian_error,
            "nested_time_grid_errors": time_grid_errors,
            "memory_prefix_errors": memory_prefix_errors,
            "momentum_quadrature_values": momentum_values,
            "momentum_quadrature_errors": momentum_errors,
        },
        "synthetic_gates": gates,
        "physical_gate_status": {
            "retarded_physical_kernel": physical_block_reason,
            "reality_of_projected_physical_equations": physical_block_reason,
            "coupled_linearized_Ward_identity": physical_block_reason,
            "UV_and_regulator_robustness": physical_block_reason,
            "physical_mode_Wronskian": physical_block_reason,
            "time_convergence": physical_block_reason,
            "momentum_convergence": physical_block_reason,
            "memory_convergence": physical_block_reason,
        },
        "execution": {
            "physical_kernel_computed": False,
            "production_curve_released": False,
            "old_v7_13_solver_or_physical_map_called": False,
            "background_series_used_as_two_time_kernel": False,
            "equations_changed": False,
            "physics_changed": False,
            "parameters_changed": False,
            "gate_thresholds_changed": False,
            "nonpass_used_as_seed": False,
        },
        "next_required": "resolve the exact c_m counterterm functional anchor, then implement the new AP1-M1 background and freeze pilot-derived physical response tolerances before any physical kernel run",
        "claim_boundary": "independent synthetic operator-algebra and discretization canaries only; no renormalized physical response, physical Ward/UV/stability result, observable, fit or significance",
    }


def main() -> None:
    import argparse

    parser = argparse.ArgumentParser()
    parser.add_argument("response_spec", type=Path)
    parser.add_argument("a3_requirements", type=Path)
    parser.add_argument("g22_checkpoint", type=Path)
    parser.add_argument("structural_preflight", type=Path)
    parser.add_argument("local_manifest", type=Path)
    parser.add_argument("--output", type=Path)
    args = parser.parse_args()
    report = build_reference_report(
        args.response_spec,
        args.a3_requirements,
        args.g22_checkpoint,
        args.structural_preflight,
        args.local_manifest,
    )
    rendered = json.dumps(report, indent=2) + "\n"
    if args.output is None:
        print(rendered, end="")
    else:
        args.output.write_text(rendered, encoding="utf-8")


if __name__ == "__main__":
    main()
