import json
import pandas as pd
import PySAM.Battery as Battery
import PySAM.GenericSystem as GenericSystem
import PySAM.Grid as Grid
import PySAM.Singleowner as SingleOwner
import PySAM.Utilityrate5 as UtilityRate
from numpy.testing import assert_allclose

#================= Read input parameter json files previously exported from SAM UI =====================================

# List of module names for a Generic Battery, Single Owner simulation. The order must be the same as the execution order
module_names = [
    "generic_system",
    "battery",
    "grid",
    "utilityrate5",
    "singleowner",
]

# Create list of filenames, per naming convention of json files
file_names = [
    "GenericBatterySingleOwner_" + x + ".json" for x in module_names
]

# read files
module_inputs = []
for f in file_names:
    with open(f, "r") as file:
        try:
            module_inputs.append(json.load(file))
        except IOError as e:
            raise IOError("Error when reading SAM json files" + str(e))

#================= Use these inputs to execute using PySAM =============================================================

# initialize the primary module (Generic System)
gs = GenericSystem.new()

# initialize the subsequent modules, linking them to the primary module
batt = Battery.from_existing(gs)
gr = Grid.from_existing(gs)
ur = UtilityRate.from_existing(gs)
so = SingleOwner.from_existing(gs)

# Create a list of modules. The execution order must be correct
modules = [gs, batt, gr, ur, so]

# transfer input from module_inputs list to the modules
for m, data in zip(modules, module_inputs):
    # Loop through each key-value pair
    for k, v in data.items():
        if k != "number_inputs":
            k = k.replace(
                "adjust_", ""
            )  # workaround for known bug, see https://github.com/NREL/pysam/issues/164
            try:
                m.value(k, v)
            except Exception as e:  # Catch any exception
                raise Exception(
                    f"Error with key: {k}, value: {v}. Original error: {e}"
                )

# execute pySAM modules in sequence
for m in modules:
    m.execute()

#================= Compare PySAM output to SAM UI output   =============================================================

# read output file generated by SAM UI
sam_ui_result = pd.read_csv( "sam_ui_output_v20231217r2.csv")

# assess whether output is the same
try:
    assert_allclose(
        modules[1].SystemOutput.gen[:],
        sam_ui_result["System power generated | (kW)"][:],
        rtol=1e-3,
        atol=0.1,
    )
except AssertionError:
    raise AssertionError("Output of SAM UI and pySAM do not match")