"""Quick test: verify WorkerResult.data contains actual records.

Uses a fake attendance register as the UniVerse DB fixture.
Records are dynamic arrays (AM-delimited strings) matching what uopy
File.read() would return.
"""
from __future__ import annotations

import time
from collections import Counter
from typing import Any

from universe_reads import run
from universe_reads.metrics import format_summary
from test_data import (
    AM,
    VM,
    PRIME_DICT,
    PICK_DICT,
    FIELD_ORDER,
    generate_attendance_register,
    dynamic_array_to_record,
)


NUM_RECORDS = 1_000_000

STATUS_LABELS = {"P": "Present", "A": "Absent", "L": "Late", "E": "Excused"}


# -------------------------------------------------------------------
# Stats helpers
# -------------------------------------------------------------------

def _print_section(title: str) -> None:
    print("\n" + "=" * 60)
    print("  %s" % title)
    print("=" * 60)


def _pct(n: int, total: int) -> str:
    return "%.1f%%" % (100 * n / total) if total else "0.0%"


def print_stats(records: dict[str, dict[str, Any]]) -> None:
    """Print statistics for a parsed attendance register."""
    total = len(records)
    if total == 0:
        print("(no records)")
        return

    # ---- Overall ----
    _print_section("Overall")
    print("  Total records : %d" % total)

    # ---- Attendance status breakdown ----
    status_counts: Counter[str] = Counter()
    class_counts: Counter[str] = Counter()
    student_counts: Counter[str] = Counter()
    date_set: set[str] = set()
    multi_value_notes = 0
    notes_present = 0

    for rec in records.values():
        status = rec["STATUS"]
        status_counts[status] += 1
        class_counts[rec["CLASS"]] += 1
        student_counts[rec["STUDENT_ID"]] += 1
        date_set.add(rec["DATE"])

        notes = rec["NOTES"]
        if isinstance(notes, list):
            multi_value_notes += 1
            if any(n for n in notes):
                notes_present += 1
        elif notes:
            notes_present += 1

    _print_section("Attendance Breakdown")
    for code in ("P", "A", "L", "E"):
        count = status_counts.get(code, 0)
        label = STATUS_LABELS.get(code, code)
        bar = "█" * int(40 * count / total)
        print("  %-8s  %4d  %6s  %s" % (label, count, _pct(count, total), bar))

    # ---- Per-class ----
    _print_section("Per Class")
    for cls in sorted(class_counts):
        n = class_counts[cls]
        # Status breakdown within this class.
        cls_status: Counter[str] = Counter()
        for rec in records.values():
            if rec["CLASS"] == cls:
                cls_status[rec["STATUS"]] += 1
        status_str = "  ".join(
            "%s=%d" % (s, cls_status.get(s, 0)) for s in ("P", "A", "L", "E")
        )
        print("  %-10s  %4d records   %s" % (cls, n, status_str))

    # ---- Per-student summary ----
    _print_section("Per Student (top 10 by record count)")
    top_students = student_counts.most_common(10)
    for sid, n in top_students:
        # Find student name from any record with this ID.
        name = next(
            (rec["STUDENT_NAME"] for rec in records.values() if rec["STUDENT_ID"] == sid),
            "?",
        )
        print("  %-10s  %-22s  %3d records" % (sid, name, n))

    # ---- Date coverage ----
    sorted_dates = sorted(date_set)
    _print_section("Date Coverage")
    print("  Unique dates : %d" % len(sorted_dates))
    if sorted_dates:
        print("  First        : %s" % sorted_dates[0])
        print("  Last         : %s" % sorted_dates[-1])

    # ---- Notes / multi-value ----
    _print_section("Notes")
    print("  Records with notes             : %d  (%s)" % (notes_present, _pct(notes_present, total)))
    print("  Records with multi-value notes : %d  (%s)" % (multi_value_notes, _pct(multi_value_notes, total)))

    # ---- Dynamic array field summary ----
    _print_section("Data Dictionary Fields")
    print("  %-15s  %s  %s  %s" % ("Field", "Attr#", "Conv", "S/M"))
    print("  " + "-" * 45)
    for name in FIELD_ORDER:
        entry = PRIME_DICT[name]
        print("  %-15s  %5d  %-4s  %s" % (name, entry.field_no, entry.conversion or "-", entry.sm))


# -------------------------------------------------------------------
# Main
# -------------------------------------------------------------------

def main() -> None:
    timings: dict[str, float] = {}
    t_total = time.perf_counter()

    # Generate a fake attendance register with realistic records.
    t0 = time.perf_counter()
    attendance = generate_attendance_register(n=NUM_RECORDS, seed=42)
    timings["Fixture generation"] = time.perf_counter() - t0

    print("Fixture: %d attendance records generated" % len(attendance))
    sample_key = list(attendance.keys())[0]
    raw_sample = attendance[sample_key]
    print("Sample key       : %s" % sample_key)
    print("Sample raw record: %s" % repr(raw_sample))
    parsed = dynamic_array_to_record(raw_sample)
    print("Sample parsed    : %s" % parsed)
    print()

    # Run the parallel reader in dry-run mode with the fixture data.
    t0 = time.perf_counter()
    results = run(
        file_name="ATTENDANCE",
        dry_run=len(attendance),
        dry_run_data=attendance,
        sessions=3,
        count_only=False,
    )
    timings["Parallel read"] = time.perf_counter() - t0

    # Merge records from all workers.
    total_data: dict[str, str] = {}
    for r in results:
        print(
            "worker-%d: records=%d data_keys=%d errors=%d"
            % (r.worker_id, r.records, len(r.data), r.errors)
        )
        total_data.update(r.data)

    print("\nTotal records returned: %d" % len(total_data))

    # Enhanced metrics — format_summary table
    read_elapsed = timings["Parallel read"]
    print(format_summary(results, wall_seconds=read_elapsed))

    # Show a few parsed records.
    print("\nSample records (raw → parsed via Prime dict):")
    for key, raw in list(total_data.items())[:5]:
        rec = dynamic_array_to_record(raw, style="prime")
        print("  %-35s  %s" % (key, rec))

    # Show a few parsed records.
    print("\nSample records (raw → parsed via Pick dict):")
    for key, raw in list(total_data.items())[:5]:
        rec = dynamic_array_to_record(raw, style="pick")
        print("  %-35s  %s" % (key, rec))

    # ---------------------------------------------------------------
    # Assertions
    # ---------------------------------------------------------------
    t0 = time.perf_counter()

    # Verify we got all of them back.
    assert len(total_data) == NUM_RECORDS, (
        "Expected %d records, got %d" % (NUM_RECORDS, len(total_data))
    )

    # Spot-check: records are dynamic arrays, and parse correctly with both styles.
    for key in list(total_data.keys())[:10]:
        raw = total_data[key]
        assert isinstance(raw, str), "Expected str (dynamic array), got %s" % type(raw)
        assert AM in raw, "Record %s should contain attribute marks" % key

        # Parse with both dict styles — results should match.
        prime_rec = dynamic_array_to_record(raw, style="prime")
        pick_rec = dynamic_array_to_record(raw, style="pick")

        assert prime_rec == pick_rec, (
            "Prime and Pick parse should match for %s" % key
        )

        assert "STUDENT_NAME" in prime_rec, "Missing STUDENT_NAME in %s" % key
        assert prime_rec["STATUS"] in ("P", "A", "L", "E"), (
            "Unexpected STATUS=%s in %s" % (prime_rec["STATUS"], key)
        )

    # Verify dictionary definitions are consistent.
    for name in PRIME_DICT:
        assert name in PICK_DICT, "Prime dict has %s but Pick dict doesn't" % name
        assert PRIME_DICT[name].field_no == PICK_DICT[name].field_no, (
            "Field number mismatch for %s" % name
        )

    timings["Assertions"] = time.perf_counter() - t0

    print("\nPASS: all %d attendance records returned as dynamic arrays" % NUM_RECORDS)
    print("      Both Prime and Pick dictionaries parse correctly")

    # ---------------------------------------------------------------
    # Stats
    # ---------------------------------------------------------------
    t0 = time.perf_counter()

    parsed_records = {
        key: dynamic_array_to_record(raw) for key, raw in total_data.items()
    }
    print_stats(parsed_records)
    timings["Stats (incl. parsing)"] = time.perf_counter() - t0

    # ---------------------------------------------------------------
    # Timing summary
    # ---------------------------------------------------------------
    timings["Total"] = time.perf_counter() - t_total

    _print_section("Timing")
    for label, secs in timings.items():
        print("  %-25s  %8.3f ms" % (label, secs * 1000))


if __name__ == "__main__":
    main()
