# import matplotlib
# matplotlib.use('Qt5Agg')  # Prevents `Invalid DISPLAY variable` errors

import pytest
import tempfile

from calliope import Model
from calliope.utils import AttrDict

from calliope import analysis

from . import common
from .common import assert_almost_equal, solver, solver_io

import matplotlib.pyplot as plt
plt.switch_backend('agg')  # Prevents `Invalid DISPLAY variable` errors


class TestModel:
    @pytest.fixture(scope='module')
    def model(self):
        locations = """
            locations:
                1:
                    techs: ['ccgt', 'demand_power']
                    override:
                        ccgt:
                            constraints:
                                e_cap.max: 100
                        demand_power:
                            constraints:
                                r: -50
            metadata:
                map_boundary: [-10, 35, 5, 45]
                location_coordinates:
                    1: [40, -2]
            links:
        """
        config_run = """
            mode: plan
            model: ['{techs}', '{locations}']
            subset_t: ['2005-01-01', '2005-01-02']
        """
        with tempfile.NamedTemporaryFile(delete=False) as f:
            f.write(locations.encode('utf-8'))
            f.read()
            override_dict = AttrDict({
                'solver': solver,
                'solver_io': solver_io,
            })
            model = common.simple_model(config_run=config_run,
                                        config_locations=f.name,
                                        override=override_dict)
        model.run()
        return model

    @pytest.fixture(scope='module')
    def builtin_model(self):
        model = Model()
        model.run()
        return model

    def test_plot_carrier_production(self, model):
        # Just make sure this doesn't raise any exceptions
        analysis.plot_carrier_production(model.solution)

    def test_plot_timeseries(self, model):
        # Just make sure this doesn't raise any exceptions
        analysis.plot_timeseries(model.solution,
                                 model.solution['e'].loc[dict(c='power')].sum(dim='x'),
                                 carrier='power', demand='demand_power')

    def test_plot_installed_capacities(self, model):
        # Just make sure this doesn't raise any exceptions
        analysis.plot_installed_capacities(model.solution)

    def test_plot_transmission(self, model):
        # Just make sure this doesn't raise any exceptions
        analysis.plot_transmission(model.solution, map_resolution='c')

    def test_get_delivered_cost(self, model):
        # TODO this should be tested with a more complex model
        assert_almost_equal(analysis.get_delivered_cost(model.solution), 0.1)

    def test_get_levelized_cost(self, model):
        lcoe = analysis.get_levelized_cost(model.solution)
        assert_almost_equal(lcoe.at['ccgt'], 0.1)

    def test_get_group_share(self, model):
        # TODO this should be tested with a more complex model
        share = analysis.get_group_share(model.solution, techs=['ccgt'])
        assert share == 1.0

    def test_get_unmet_demand_hours(self, builtin_model):
        # TODO this should be tested with a more complex model
        unmet = analysis.get_unmet_demand_hours(builtin_model.solution)
        assert unmet == 1

    def test_recompute_levelized_costs(self, model):
        # Cost in solution
        sol = model.solution
        assert_almost_equal(sol['summary'].to_pandas().loc['ccgt', 'levelized_cost_monetary'], 0.1)
        # Recomputed cost must be the same
        dm = analysis.SolutionModel(model.solution)
        recomputed = dm.recompute_levelized_costs('ccgt')
        assert_almost_equal(recomputed['total'], 0.1)

    def test_recompute_levelized_costs_after_changes(self, model):
        # Make changes
        dm = analysis.SolutionModel(model.solution)
        dm.config_model.techs.ccgt.costs.monetary.e_cap = 50
        dm.config_model.techs.ccgt.costs.monetary.om_fuel = 1.0
        # Recomputed cost
        recomputed = dm.recompute_levelized_costs('ccgt')
        assert_almost_equal(recomputed['total'], 1.0, tolerance=0.001)

[((333, 358), 'matplotlib.pyplot.switch_backend', 'plt.switch_backend', (['"""agg"""'], {}), "('agg')\n", (351, 358), True, 'import matplotlib.pyplot as plt\n'), ((429, 459), 'pytest.fixture', 'pytest.fixture', ([], {'scope': '"""module"""'}), "(scope='module')\n", (443, 459), False, 'import pytest\n'), ((1688, 1718), 'pytest.fixture', 'pytest.fixture', ([], {'scope': '"""module"""'}), "(scope='module')\n", (1702, 1718), False, 'import pytest\n'), ((1764, 1771), 'calliope.Model', 'Model', ([], {}), '()\n', (1769, 1771), False, 'from calliope import Model\n'), ((1932, 1980), 'calliope.analysis.plot_carrier_production', 'analysis.plot_carrier_production', (['model.solution'], {}), '(model.solution)\n', (1964, 1980), False, 'from calliope import analysis\n'), ((2415, 2465), 'calliope.analysis.plot_installed_capacities', 'analysis.plot_installed_capacities', (['model.solution'], {}), '(model.solution)\n', (2449, 2465), False, 'from calliope import analysis\n'), ((2579, 2641), 'calliope.analysis.plot_transmission', 'analysis.plot_transmission', (['model.solution'], {'map_resolution': '"""c"""'}), "(model.solution, map_resolution='c')\n", (2605, 2641), False, 'from calliope import analysis\n'), ((2892, 2935), 'calliope.analysis.get_levelized_cost', 'analysis.get_levelized_cost', (['model.solution'], {}), '(model.solution)\n', (2919, 2935), False, 'from calliope import analysis\n'), ((3109, 3165), 'calliope.analysis.get_group_share', 'analysis.get_group_share', (['model.solution'], {'techs': "['ccgt']"}), "(model.solution, techs=['ccgt'])\n", (3133, 3165), False, 'from calliope import analysis\n'), ((3332, 3387), 'calliope.analysis.get_unmet_demand_hours', 'analysis.get_unmet_demand_hours', (['builtin_model.solution'], {}), '(builtin_model.solution)\n', (3363, 3387), False, 'from calliope import analysis\n'), ((3680, 3718), 'calliope.analysis.SolutionModel', 'analysis.SolutionModel', (['model.solution'], {}), '(model.solution)\n', (3702, 3718), False, 'from calliope import analysis\n'), ((3935, 3973), 'calliope.analysis.SolutionModel', 'analysis.SolutionModel', (['model.solution'], {}), '(model.solution)\n', (3957, 3973), False, 'from calliope import analysis\n'), ((1205, 1246), 'tempfile.NamedTemporaryFile', 'tempfile.NamedTemporaryFile', ([], {'delete': '(False)'}), '(delete=False)\n', (1232, 1246), False, 'import tempfile\n'), ((1349, 1401), 'calliope.utils.AttrDict', 'AttrDict', (["{'solver': solver, 'solver_io': solver_io}"], {}), "({'solver': solver, 'solver_io': solver_io})\n", (1357, 1401), False, 'from calliope.utils import AttrDict\n'), ((2780, 2823), 'calliope.analysis.get_delivered_cost', 'analysis.get_delivered_cost', (['model.solution'], {}), '(model.solution)\n', (2807, 2823), False, 'from calliope import analysis\n')]