import json
import os
import re
from biodivine_aeon import BooleanNetwork, AsynchronousGraph, Attractors

def normalize_name(name):
    """Odstráni ne-alfanumerické znaky a prevedie na malé písmená."""
    name = name.replace('κ', 'k').replace('α', 'a').replace('β', 'b')
    return re.sub(r'[^a-zA-Z0-9]', '', name).lower()

def verify_phenotypes(model_path, json_path, report_path):
    if not os.path.exists(model_path):
        print(f"Chyba: Model {model_path} neexistuje.")
        return

    with open(model_path, 'r') as f:
        bn = BooleanNetwork.from_aeon(f.read())

    stg = AsynchronousGraph(bn)
    model_variables = bn.variable_names()
    name_map = {normalize_name(var): var for var in model_variables}

    try:
        with open(json_path, 'r', encoding='utf-8') as f:
            raw = f.read().strip()
        extracted_phenotypes = json.loads(raw) if raw else []
    except json.JSONDecodeError:
        extracted_phenotypes = []

    if isinstance(extracted_phenotypes, str):
        try:
            extracted_phenotypes = json.loads(extracted_phenotypes)
        except json.JSONDecodeError:
            extracted_phenotypes = []

    if not isinstance(extracted_phenotypes, list):
        extracted_phenotypes = []

    print(f"Počítam atraktory pre model: {model_path}...")
    try:
        attractors = Attractors.attractors(stg)
    except AttributeError:
        attractors = Attractors.compute(stg)

    total_model_attractors = len(attractors)
    print(f"Nájdených atraktorov v modeli: {total_model_attractors}")

    attractor_details = []
    for i, attr_bdd in enumerate(attractors):
        if not attr_bdd.is_empty():
            try:
                state_dict = {}
                for var_name in model_variables:
                    var_id = bn.find_variable(var_name)
                    is_true = not attr_bdd.intersect_vertices(stg.mk_subspace_vertices({var_id: True})).is_empty()
                    is_false = not attr_bdd.intersect_vertices(stg.mk_subspace_vertices({var_id: False})).is_empty()

                    if is_true and not is_false:
                        state_dict[var_name] = "stable active"
                    elif is_false and not is_true:
                        state_dict[var_name] = "stable inactive"
                    else:
                        state_dict[var_name] = "unstable"

                attractor_details.append({
                    "id": i + 1,
                    "state": state_dict
                })
            except Exception as e:
                print(f"Nepodarilo sa načítať detaily atraktora {i}: {e}")

    all_attractors_bdd = stg.mk_empty_colored_vertices()
    for attr in attractors:
        all_attractors_bdd = all_attractors_bdd.union(attr)

    verification_results = []

    for phenotype in extracted_phenotypes:
        name = phenotype.get('phenotype_name', 'Neznámy fenotyp')
        raw_variables = phenotype.get('variables', {})
        if isinstance(raw_variables, list):
            variables = {var: 'stable active' for var in raw_variables}
        else:
            variables = raw_variables

        phenotype_mask = stg.mk_unit_colored_vertices()
        valid_phenotype = True

        print(f"Overujem fenotyp: {name}")
        for raw_var_name, expected_state in variables.items():
            norm_name = normalize_name(raw_var_name)
            real_var_name = name_map.get(norm_name)

            if not real_var_name:
                print(f"  [!] Premenná '{raw_var_name}' nenájdená v modeli.")
                valid_phenotype = False
                break

            try:
                var_id = bn.find_variable(real_var_name)
                if expected_state == 'stable active':
                    mask = stg.mk_subspace_vertices({var_id: True})
                    phenotype_mask = phenotype_mask.intersect_vertices(mask)
                elif expected_state == 'stable inactive':
                    mask = stg.mk_subspace_vertices({var_id: False})
                    phenotype_mask = phenotype_mask.intersect_vertices(mask)

            except Exception as e:
                print(f"  [!] Chyba pri spracovaní {real_var_name}: {e}")
                valid_phenotype = False
                break

        is_verified = False
        if valid_phenotype:
            matching_states = all_attractors_bdd.intersect(phenotype_mask)
            is_verified = not matching_states.is_empty()

        verification_results.append({
            "phenotype": name,
            "variables": variables,
            "verified": is_verified,
            "rationale": phenotype.get('rationale', '')
        })
        print(f"  -> Výsledok: {'VERIFIED' if is_verified else 'NOT VERIFIED'}")

    final_report = {
        "model_attractors_count": total_model_attractors,
        "model_attractors_details": attractor_details,
        "extracted_phenotypes_count": len(extracted_phenotypes),
        "results": verification_results
    }

    with open(report_path, 'w', encoding='utf-8') as f:
        json.dump(final_report, f, indent=4, ensure_ascii=False)
    print(f"Verifikácia dokončená. Výsledok v: {report_path}")

if __name__ == "__main__":
    verify_phenotypes(
        "../data/models/model.aeon",
        "../data/runs/temp_phenotypes.json",
        "../data/runs/temp_report.json"
    )