"""Load and process framework data from JSON files for evaluation and analysis"""

# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/05_frameworks.ipynb.

# %% auto 0
__all__ = ['VALID_FRAMEWORKS', 'EvalDict', 'evalify', 'EvalData', 'IOMEvalData', 'FrameworkCat', 'Framework', 'FrameworkInfo',
           'find_srf_output_by_id']

# %% ../nbs/05_frameworks.ipynb 2
from pathlib import Path
from rich import print
import json
from enum import Enum
from fastcore.all import *

# %% ../nbs/05_frameworks.ipynb 4
class EvalDict(AttrDict):
    "A dictionary that truncates strings and lists to a maximum length for pretty printing and dot notation access of attributes"
    def __init__(self, *args, max_len=50, max_items=5, **kwargs):
        super().__init__(*args, **kwargs)
        self._max_len = max_len
        self._max_items = max_items
    
    def __repr__(self):
        def truncate(text, max_len=self._max_len):
            return text[:max_len] + "..." if len(text) > self._max_len else text
        
        def format_item(key, value):
            if isinstance(value, str):
                return f"'{key}': '{truncate(value)}'"
            elif isinstance(value, (list, dict)):
                count = len(value)
                return f"'{key}': [{count} items]"
            else:
                return f"'{key}': {value}"
        
        items = list(self.items())[:self._max_items]  
        formatted = [format_item(k, v) for k, v in items]
        suffix = ", ..." if len(self) > self._max_items else ""
        
        return f"EvalDict({{{', '.join(formatted)}{suffix}}})"

# %% ../nbs/05_frameworks.ipynb 5
@delegates(EvalDict.__init__)
def evalify(
    data, # data to evalify
    **kwargs # kwargs to pass to EvalDict.__init__
    ):
    "Evalify a dictionary or a list of dictionaries"
    if isinstance(data, list):
        return [EvalDict(item, **kwargs) for item in data]
    else:
        return EvalDict(data, **kwargs)

# %% ../nbs/05_frameworks.ipynb 8
class EvalData:
    def __init__(self, base_path):
        self._data = self._load_all(Path(base_path))
    
    def _load_all(self, path):
        return {f.stem: json.loads(f.read_text()) for f in path.ls(file_exts='.json')}

# %% ../nbs/05_frameworks.ipynb 9
class IOMEvalData(EvalData):
    def __init__(self, base_path="./files/eval_frameworks"):
        super().__init__(base_path)
    
    @property
    def srf_crosscutting_priorities(self): return evalify(self._data['crosscutting_priorities'])
    @property
    def gcm_srf_lut(self): return evalify(self._data['gcm_to_srf_outputs'])
    @property
    def gcm_objectives(self): return evalify(self._data['gcm'])
    @property
    def gcm_objectives_small(self): return evalify(self._data['gcm_small'])
    @property
    def srf_enablers(self): return evalify(self._data['srf_enablers'])
    @property 
    def srf_objectives(self): return evalify(self._data['srf_objectives'])
    @property
    def srf_gcm_lut(self): return evalify(self._data['srf_outputs_to_gcm'])

# %% ../nbs/05_frameworks.ipynb 17
class FrameworkCat(Enum):
    ENABLERS = "Enablers"
    CROSSCUT = "Crosscutting Priorities"
    OBJS = "Objectives"
    OUTPUTS = "Outputs"
    def __str__(self): return self.value

# %% ../nbs/05_frameworks.ipynb 19
class Framework(Enum):
    "Framework type"
    SRF = "SRF"
    GCM = "GCM"
    def __str__(self): return self.value

# %% ../nbs/05_frameworks.ipynb 20
VALID_FRAMEWORKS = {
    Framework.SRF: [FrameworkCat.ENABLERS,  FrameworkCat.CROSSCUT, FrameworkCat.OBJS, FrameworkCat.OUTPUTS],
    Framework.GCM: [FrameworkCat.OBJS]
}

# %% ../nbs/05_frameworks.ipynb 21
class FrameworkInfo(AttrDict):
    def __init__(self, 
                 name,  # Framework name
                 category,  # Framework category
                 theme_id  # Theme identifier (e.g. "4" for "Data and evidence" in SRF Enablers)
                 ): 
        "Framework information"
        if name not in VALID_FRAMEWORKS: raise ValueError(f"Invalid framework: {name}")
        if category not in VALID_FRAMEWORKS[name]: raise ValueError(f"Invalid category for {name}: {category}")
        self.category = str(category)
        self.theme_id = theme_id
        self.name = str(name)

# %% ../nbs/05_frameworks.ipynb 23
def find_srf_output_by_id(
    eval_data: EvalData, # EvalData
    output_id: str # SRF output ID
    ) -> dict: # SRF output with its full hierarchical context
    "Find SRF output and return it with its full hierarchical context."
    for obj in eval_data.srf_objectives:
        for long_out in obj.get('long_term_outcomes', []):
            for short_out in long_out.get('short_term_outcomes', []):
                output = next((o for o in short_out.get('outputs', []) if o['id'] == output_id), None)
                if output:
                    return {'objective': obj, 'long_outcome': long_out, 'short_outcome': short_out, 'output': output}
    return None
