"""
Parsers for Mids Reborn's *text*-based .mhd files. These are NOT binary -
they're tab-delimited lines read via a StreamReader, matching the
FileIO.IOGrab / IOSeek helpers in MidsReborn/Core/FileIO.cs.

IOGrab: read one line, split on '\t', then per-field: strip a leading
"'" or leading space, strip a trailing space, and strip any '"' chars.
IOSeek(needle): keep reading lines until strArray[0] == needle.

Field orders/section markers verified against MidsReborn/Core/DatabaseAPI.cs:
  LoadMaths            (Maths.mhd)
  LoadOrigins          (Origins.mhd)
  LoadLevelsDatabase    (NLevels.mhd / RLevels.mhd)
  LoadEnhancementClasses (EClasses.mhd)
"""


def io_strip(s):
    if s.startswith("'") or s.startswith(" "):
        s = s[1:]
    if s.endswith(" "):
        s = s[:-1]
    return s.replace('"', "")


def io_grab(lines_iter):
    """Returns the next non-empty line's tab-split, IOStrip'ed fields, or None at EOF."""
    line = next(lines_iter, None)
    if line is None:
        return None
    line = line.rstrip("\n").rstrip("\r")
    if line == "":
        return []
    return [io_strip(f) for f in line.split("\t")]


def io_seek(lines_iter, needle):
    while True:
        fields = io_grab(lines_iter)
        if fields is None:
            raise EOFError(f"IOSeek: reached EOF looking for {needle!r}")
        if fields and fields[0] == needle:
            return fields


def _lines_iter(path):
    with open(path, "r", encoding="utf-8", errors="replace") as f:
        for line in f:
            yield line


def parse_origins(path):
    it = _lines_iter(path)
    io_seek(it, "Version:")
    io_seek(it, "Origin")
    origins = []
    while True:
        fields = io_grab(it)
        if fields is None or fields[0] == "End":
            break
        origins.append({"name": fields[0], "field1": fields[1], "field2": fields[2]})
    return origins


def parse_eclasses(path):
    it = _lines_iter(path)
    io_seek(it, "Version:")
    io_seek(it, "Index")
    classes = []
    while True:
        fields = io_grab(it)
        if fields is None or fields[0] == "End":
            break
        classes.append({
            "id": int(fields[0]),
            "name": fields[1],
            "short_name": fields[2],
            "class_id": fields[3],
            "desc": fields[4],
        })
    return classes


def parse_levels(path):
    """NLevels.mhd (normal build mode) / RLevels.mhd (respec mode): 50 rows of
    level-up data. Mids reads these into a fixed-size LevelMap[50] array; field
    meaning beyond the row label isn't critical for us yet, so rows are kept as
    raw label + values for now."""
    it = _lines_iter(path)
    io_seek(it, "Level")
    levels = []
    for _ in range(50):
        fields = io_grab(it)
        levels.append(fields)
    return levels


def parse_maths(path):
    it = _lines_iter(path)
    io_seek(it, "Version:")
    io_seek(it, "EDRT")

    # 3 rows x 4 schedules (A/B/C/D) of ED breakpoints
    mult_ed = [[0.0, 0.0, 0.0] for _ in range(4)]  # [schedule][breakpoint]
    for breakpoint_idx in range(3):
        fields = io_grab(it)
        for schedule_idx in range(4):
            mult_ed[schedule_idx][breakpoint_idx] = float(fields[schedule_idx + 1])

    io_seek(it, "EGE")
    mult_to = [float(x) for x in io_grab(it)[1:5]]
    mult_do = [float(x) for x in io_grab(it)[1:5]]
    mult_so = [float(x) for x in io_grab(it)[1:5]]
    mult_ho = [float(x) for x in io_grab(it)[1:5]]

    io_seek(it, "LBIOE")
    mult_io = []
    for _ in range(53):
        fields = io_grab(it)
        mult_io.append([float(x) for x in fields[1:5]])

    return {
        "mult_ed_by_schedule": {"A": mult_ed[0], "B": mult_ed[1], "C": mult_ed[2], "D": mult_ed[3]},
        "mult_to": mult_to,
        "mult_do": mult_do,
        "mult_so": mult_so,
        "mult_ho": mult_ho,
        "mult_io_by_level": mult_io,
    }


def apply_ed(schedule_breakpoints, value):
    """Mirrors Enhancement.ApplyED from MidsReborn/Core/Enhancement.cs: the
    Enhancement Diversification curve. schedule_breakpoints = [ed0, ed1, ed2]
    for the relevant schedule (A/B/C/D)."""
    ed0, ed1, ed2 = schedule_breakpoints
    if value <= ed0:
        return value
    edm0 = ed0
    edm1 = ed0 + (ed1 - ed0) * 0.9
    edm2 = edm1 + (ed2 - ed1) * 0.7
    if value > ed1:
        if value > ed2:
            return edm2 + (value - ed2) * 0.15
        return edm1 + (value - ed1) * 0.7
    return edm0 + (value - ed0) * 0.9


if __name__ == "__main__":
    import json
    import sys

    base = "/home/claude/mids-reborn/MidsReborn/Databases/Homecoming"
    origins = parse_origins(f"{base}/Origins.mhd")
    eclasses = parse_eclasses(f"{base}/EClasses.mhd")
    maths = parse_maths(f"{base}/Maths.mhd")
    nlevels = parse_levels(f"{base}/NLevels.mhd")

    print("origins:", origins, file=sys.stderr)
    print("eclasses (first 3):", eclasses[:3], file=sys.stderr)
    print("maths ED schedules:", json.dumps(maths["mult_ed_by_schedule"]), file=sys.stderr)
    print("nlevels row 0:", nlevels[0], file=sys.stderr)

    # Sanity-check the ED curve: known CoH behavior is ~90% effectiveness in the
    # second tier, ~70% in the third, ~15% beyond.
    sched_a = maths["mult_ed_by_schedule"]["A"]
    print(f"Schedule A breakpoints: {sched_a}", file=sys.stderr)
    for test_val in [0.3, 0.6, 0.9, 1.2]:
        print(f"  ED(A, {test_val}) = {apply_ed(sched_a, test_val):.4f}", file=sys.stderr)
