"""
Parses I12.mhd -> archetypes[], powersets[], powers[], entities[]

Field order verified against:
  MidsReborn/Core/Base/Data_Classes/Archetype.cs  (Archetype(BinaryReader))
  MidsReborn/Core/Powerset.cs                     (Powerset(BinaryReader))
  MidsReborn/Core/Requirement.cs                  (Requirement(BinaryReader))
  MidsReborn/Core/Base/Data_Classes/Power.cs       (Power(BinaryReader))
  MidsReborn/Core/SummonedEntity.cs                (SummonedEntity(BinaryReader))
  MidsReborn/Core/DatabaseAPI.cs                   (top-level section markers)
"""
from mhd_reader import MhdReader
from effect_schema import read_effect
from enums import (
    E_CLASS_TYPE, E_MODE_FLAGS, E_POWER_TYPE, E_VECTOR_FLAGS, E_EFFECT_AREA,
    E_ENTITY_FLAGS, E_CAST_FLAGS, E_NOTIFY, E_ENHANCE, E_GRID_TYPE, E_SUMMON_ENTITY,
    E_POWERSET_TYPE, name_of, flags_of,
)

HEADER_START = "Mids Reborn Powers Database"
HEADER_ARCHETYPES = "BEGIN:ARCHETYPES"
HEADER_POWERSETS = "BEGIN:POWERSETS"
HEADER_POWERS = "BEGIN:POWERS"
HEADER_SUMMONS = "BEGIN:SUMMONS"


def read_archetype(r, idx):
    d = {"idx": idx}
    d["display_name"] = r.read_string()
    d["hitpoints"] = r.read_int32()
    d["hp_cap"] = r.read_single()
    d["desc_long"] = r.read_string()
    d["res_cap"] = r.read_single()
    d["origin"] = r.read_string_array()
    d["class_name"] = r.read_string()
    d["class_type"] = name_of(E_CLASS_TYPE, r.read_int32())
    d["column"] = r.read_int32()
    d["desc_short"] = r.read_string()
    d["primary_group"] = r.read_string()
    d["secondary_group"] = r.read_string()
    d["playable"] = r.read_boolean()
    d["recharge_cap"] = r.read_single()
    d["damage_cap"] = r.read_single()
    d["recovery_cap"] = r.read_single()
    d["regen_cap"] = r.read_single()
    d["base_recovery"] = r.read_single()
    d["base_regen"] = r.read_single()
    d["base_threat"] = r.read_single()
    d["perception_cap"] = r.read_single()
    return d


def read_powerset(r, idx):
    d = {"n_id": idx}
    d["display_name"] = r.read_string()
    d["n_archetype"] = r.read_int32()
    d["set_type"] = name_of(E_POWERSET_TYPE, r.read_int32())
    d["image_name"] = r.read_string()
    full_name = r.read_string()
    if not full_name:
        full_name = "Orphan." + d["display_name"].replace(" ", "_")
    d["full_name"] = full_name
    d["set_name"] = r.read_string()
    d["description"] = r.read_string()
    d["sub_name"] = r.read_string()
    d["at_class"] = r.read_string()
    d["uid_trunk_set"] = r.read_string()
    d["uid_link_secondary"] = r.read_string()

    mutex_count = r.read_int32() + 1
    uid_mutex_sets = []
    nid_mutex_sets = []
    for _ in range(mutex_count):
        uid_mutex_sets.append(r.read_string())
        nid_mutex_sets.append(r.read_int32())
    d["uid_mutex_sets"] = uid_mutex_sets
    d["nid_mutex_sets"] = nid_mutex_sets
    return d


def read_requirement(r):
    d = {}
    class_name_count = r.read_int32() + 1
    d["class_name"] = [r.read_string() for _ in range(class_name_count)]
    class_name_not_count = r.read_int32() + 1
    d["class_name_not"] = [r.read_string() for _ in range(class_name_not_count)]
    power_id_count = r.read_int32() + 1
    d["power_id"] = [[r.read_string(), r.read_string()] for _ in range(power_id_count)]
    power_id_not_count = r.read_int32() + 1
    d["power_id_not"] = [[r.read_string(), r.read_string()] for _ in range(power_id_not_count)]
    return d


def read_power(r, idx):
    d = {"idx_in_file": idx}
    d["static_index"] = r.read_int32()
    d["full_name"] = r.read_string()
    d["group_name"] = r.read_string()
    d["set_name"] = r.read_string()
    d["power_name"] = r.read_string()
    d["display_name"] = r.read_string()
    d["available"] = r.read_int32()
    d["requires"] = read_requirement(r)
    d["modes_required"] = flags_of(E_MODE_FLAGS, r.read_int32())
    d["modes_disallowed"] = flags_of(E_MODE_FLAGS, r.read_int32())
    d["power_type"] = name_of(E_POWER_TYPE, r.read_int32())
    d["accuracy"] = r.read_single()
    d["attack_types"] = flags_of(E_VECTOR_FLAGS, r.read_int32())

    group_membership_count = r.read_int32() + 1
    d["group_membership"] = [r.read_string() for _ in range(group_membership_count)]

    d["entities_affected"] = flags_of(E_ENTITY_FLAGS, r.read_int32())
    d["entities_auto_hit"] = flags_of(E_ENTITY_FLAGS, r.read_int32())
    d["target"] = flags_of(E_ENTITY_FLAGS, r.read_int32())
    d["target_los"] = r.read_boolean()
    d["range"] = r.read_single()
    d["target_secondary"] = flags_of(E_ENTITY_FLAGS, r.read_int32())
    d["range_secondary"] = r.read_single()
    d["end_cost"] = r.read_single()
    d["interrupt_time"] = r.read_single()
    d["cast_time"] = r.read_single()
    d["recharge_time"] = r.read_single()
    d["base_recharge_time"] = r.read_single()
    d["activate_period"] = r.read_single()
    d["effect_area"] = name_of(E_EFFECT_AREA, r.read_int32())
    d["radius"] = r.read_single()
    d["arc"] = r.read_int32()
    d["max_targets"] = r.read_int32()
    d["max_boosts"] = r.read_string()
    d["cast_flags"] = flags_of(E_CAST_FLAGS, r.read_int32())
    d["ai_report"] = name_of(E_NOTIFY, r.read_int32())
    d["num_charges"] = r.read_int32()
    d["usage_time"] = r.read_int32()
    d["life_time"] = r.read_int32()
    d["life_time_in_game"] = r.read_int32()
    d["num_allowed"] = r.read_int32()
    d["do_not_save"] = r.read_boolean()

    boosts_allowed_count = r.read_int32() + 1
    d["boosts_allowed"] = [r.read_string() for _ in range(boosts_allowed_count)]

    d["cast_through_hold"] = r.read_boolean()
    d["ignore_strength"] = r.read_boolean()
    d["desc_short"] = r.read_string()
    d["desc_long"] = r.read_string()

    d["enhancements_allowed_raw"] = r.read_int32_array()  # legacy eEnhance flags array

    set_type_count = r.read_int32() + 1
    d["set_types"] = [r.read_int32() for _ in range(set_type_count)]

    d["click_buff"] = r.read_boolean()
    d["always_toggle"] = r.read_boolean()
    d["level"] = r.read_int32()
    d["allow_front_loading"] = r.read_boolean()
    d["variable_enabled"] = r.read_boolean()
    d["variable_override"] = r.read_boolean()
    d["variable_name"] = r.read_string()
    d["variable_min"] = r.read_int32()
    d["variable_max"] = r.read_int32()

    uid_subpower_count = r.read_int32() + 1
    d["uid_sub_power"] = [r.read_string() for _ in range(uid_subpower_count)]

    ignore_enh_count = r.read_int32() + 1
    d["ignore_enh"] = [name_of(E_ENHANCE, r.read_int32()) for _ in range(ignore_enh_count)]

    ignore_buff_count = r.read_int32() + 1
    d["ignore_buff"] = [name_of(E_ENHANCE, r.read_int32()) for _ in range(ignore_buff_count)]

    d["skip_max"] = r.read_boolean()
    d["inherent_type"] = name_of(E_GRID_TYPE, r.read_int32())
    d["display_location"] = r.read_int32()
    d["mutex_auto"] = r.read_boolean()
    d["mutex_ignore"] = r.read_boolean()
    d["absorb_summon_effects"] = r.read_boolean()
    d["absorb_summon_attributes"] = r.read_boolean()
    d["show_summon_anyway"] = r.read_boolean()
    d["never_auto_update"] = r.read_boolean()
    d["never_auto_update_requirements"] = r.read_boolean()
    d["include_flag"] = r.read_boolean()
    d["forced_class"] = r.read_string()
    d["sort_override"] = r.read_boolean()
    d["boost_boostable"] = r.read_boolean()
    d["boost_use_player_level"] = r.read_boolean()

    effect_count = r.read_int32() + 1
    d["effects"] = [read_effect(r) for _ in range(effect_count)]

    d["hidden_power"] = r.read_boolean()
    d["active"] = r.read_boolean()
    d["taken"] = r.read_boolean()
    d["stacks"] = r.read_int32()
    d["variable_start"] = r.read_int32()
    return d


def read_summoned_entity(r):
    d = {}
    d["uid"] = r.read_string()
    d["display_name"] = r.read_string()
    d["entity_type"] = name_of(E_SUMMON_ENTITY, r.read_int32())
    d["class_name"] = r.read_string()

    powerset_count = r.read_int32()
    d["powerset_full_name"] = [r.read_string() for _ in range(powerset_count)]

    upgrade_count = r.read_int32()
    d["upgrade_power_full_name"] = [r.read_string() for _ in range(upgrade_count)]
    return d


def parse_powers_db(path, progress_every=2000):
    r = MhdReader(path)
    try:
        r.expect_string(HEADER_START)
        version = r.read_string()
        year = r.read_int32()
        date = None
        if year > 0:
            month = r.read_int32()
            day = r.read_int32()
            date = f"{year:04d}-{month:02d}-{day:02d}"
        else:
            r.read_int64()  # DateTime.FromBinary ticks - not decoded, rarely used
        issue = r.read_int32()
        page_vol = r.read_int32()
        page_vol_text = r.read_string()

        meta = {
            "version": version, "date": date, "issue": issue,
            "page_vol": page_vol, "page_vol_text": page_vol_text,
        }

        r.expect_string(HEADER_ARCHETYPES)
        at_count = r.read_int32() + 1
        archetypes = [read_archetype(r, i) for i in range(at_count)]

        r.expect_string(HEADER_POWERSETS)
        ps_count = r.read_int32() + 1
        powersets = []
        for i in range(ps_count):
            powersets.append(read_powerset(r, i))
            if progress_every and i % progress_every == 0:
                print(f"  powersets: {i}/{ps_count}", flush=True)

        r.expect_string(HEADER_POWERS)
        pw_count = r.read_int32() + 1
        powers = []
        for i in range(pw_count):
            powers.append(read_power(r, i))
            if progress_every and i % progress_every == 0:
                print(f"  powers: {i}/{pw_count}", flush=True)

        r.expect_string(HEADER_SUMMONS)
        ent_count = r.read_int32() + 1
        entities = [read_summoned_entity(r) for _ in range(ent_count)]

        return {
            "meta": meta,
            "archetypes": archetypes,
            "powersets": powersets,
            "powers": powers,
            "entities": entities,
        }
    finally:
        r.close()


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

    path = sys.argv[1] if len(sys.argv) > 1 else \
        "/home/claude/mids-reborn/MidsReborn/Databases/Homecoming/I12.mhd"
    result = parse_powers_db(path)
    print(
        f"meta={result['meta']} "
        f"archetypes={len(result['archetypes'])} "
        f"powersets={len(result['powersets'])} "
        f"powers={len(result['powers'])} "
        f"entities={len(result['entities'])}",
        file=sys.stderr,
    )
