#!/usr/bin/env python3
"""Compare two OpticsFEM COO exports (Ai/Aj/Av, Bv_real/Bv_imag)."""

from __future__ import annotations

import argparse
from pathlib import Path

import numpy as np
from scipy import sparse


def load_coo(prefix: Path) -> tuple[sparse.csr_matrix, np.ndarray]:
    ai = np.loadtxt(prefix / "Ai.txt", dtype=np.int64)
    aj = np.loadtxt(prefix / "Aj.txt", dtype=np.int64)
    av: list[complex] = []
    for line in (prefix / "Av.txt").read_text(encoding="utf-8", errors="ignore").splitlines():
        line = line.strip()
        if not line:
            continue
        if line.startswith("(") and line.endswith(")"):
            re_s, im_s = line[1:-1].split(",")
            av.append(complex(float(re_s), float(im_s)))
        else:
            av.append(complex(float(line)))
    a = sparse.coo_matrix((np.asarray(av), (ai, aj))).tocsr()
    br = np.loadtxt(prefix / "Bv_real.txt")
    bi = np.loadtxt(prefix / "Bv_imag.txt")
    b = br + 1j * bi
    return a, b


def main() -> int:
    ap = argparse.ArgumentParser(description=__doc__)
    ap.add_argument("ref", type=Path, help="reference directory (e.g. MATLAB OutFile_fem4_ab)")
    ap.add_argument("other", type=Path, help="other directory (e.g. C++ OutFile)")
    args = ap.parse_args()

    a_ref, b_ref = load_coo(args.ref)
    a_other, b_other = load_coo(args.other)

    print(f"ref:   n={a_ref.shape[0]} nnz={a_ref.nnz} |b|={np.linalg.norm(b_ref):.6g}")
    print(f"other: n={a_other.shape[0]} nnz={a_other.nnz} |b|={np.linalg.norm(b_other):.6g}")

    if a_ref.shape != a_other.shape:
        print("[FAIL] matrix shape mismatch")
        return 1
    if b_ref.size != b_other.size:
        print("[FAIL] b length mismatch")
        return 1

    d = a_ref - a_other
    max_abs = abs(d).max()
    nnz_diff = d.nnz
    rel = max_abs / max(abs(a_ref).max(), 1e-30)
    print(f"A max|diff|={max_abs:.6g}  rel={rel:.6g}  nnz(diff)={nnz_diff}")

    b_diff = np.max(np.abs(b_ref - b_other))
    print(f"b max|diff|={b_diff:.6g}")

    if max_abs < 1e-9 and b_diff < 1e-9:
        print("[OK] matrices match within 1e-9")
        return 0
    if max_abs < 1e-6 and b_diff < 1e-6:
        print("[WARN] close but not identical")
        return 0
    print("[FAIL] significant difference")
    return 2


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