# WeatherParametersList.py -- Pamhyr
# Copyright (C) 2023-2025  INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.

# -*- coding: utf-8 -*-

from copy import copy
from tools import trace, timer

from Model.Tools.PamhyrListExt import PamhyrModelList
from Model.Except import NotImplementedMethodeError

from Model.WeatherParameters.WeatherParameters import (
    WeatherParameters,
    WeatherParametersDefault,
)
from Model.WeatherParameters.WeatherParametersTypes import (
    NotDefined, WeatherParam, AirTemperature, SpecificHumidity,
    GlobalRadiation, ReferenceWindSpeed, GroundwaterTemperature,
    GroundwaterFlowRate, Albedo, ShadingCoefficient, CloudCoverFraction
)


class WeatherParametersList(PamhyrModelList):
    _sub_classes = [
        WeatherParameters,
    ]
    _default_types = [
        "AT", "SH", "GR", "RWS", "GT", "GFR", "ALB", "SC", "CCF"
    ]

    def __init__(self, status=None):
        super(WeatherParametersList, self).__init__(status=status)
        self._default = []
        self._init_missing_default_values()

    @classmethod
    def _db_load(cls, execute, data=None):
        new = cls(status=data['status'])

        if data is None:
            data = {}

        new._lst = WeatherParameters._db_load(
            execute, data
        )

        data['loaded_pid'] = set()
        new._default = WeatherParametersDefault._db_load(
            execute, data
        )
        new._init_missing_default_values()
        new._sort_default_values()

        return new

    def _db_save(self, execute, data=None):
        execute(
            "DELETE FROM weather_parameters " +
            f"WHERE scenario = {self._status.scenario_id}"
        )
        execute(
            "DELETE FROM weather_parameters_data " +
            f"WHERE scenario = {self._status.scenario_id}"
        )
        execute(
            "DELETE FROM weather_parameters_default " +
            f"WHERE scenario = {self._status.scenario_id}"
        )

        if data is None:
            data = {}

        for wp in self._lst:
            wp._db_save(execute, data=data)

        for wp_default in self._default:
            wp_default._db_save(execute, data=data)

        return True

    def _data_traversal(self,
                        predicate=lambda obj, data: True,
                        modifier=lambda obj, data: None,
                        data={}):
        if predicate(self, data):
            modifier(self, data)

        for el in self._lst:
            el._data_traversal(predicate, modifier, data)

        for el in self._default:
            el._data_traversal(predicate, modifier, data)

    def _init_missing_default_values(self):
        existing = [wp_default.type for wp_default in self.default]
        for type in self._default_types:
            if type not in existing:
                self._default.append(
                    WeatherParametersDefault(type=type, status=self._status)
                )

        self._sort_default_values()

    def _sort_default_values(self):
        self._default.sort(
            key=lambda wp_default: self._default_types.index(wp_default.type)
            if wp_default.type in self._default_types
            else len(self._default_types)
        )

    def new(self, index, type="ND"):
        if type == "AT":
            n = AirTemperature(status=self._status)
        elif type == "SH":
            n = SpecificHumidity(status=self._status)
        elif type == "GR":
            n = GlobalRadiation(status=self._status)
        elif type == "RWS":
            n = ReferenceWindSpeed(status=self._status)
        elif type == "GT":
            n = GroundwaterTemperature(status=self._status)
        elif type == "GFR":
            n = GroundwaterFlowRate(status=self._status)
        elif type == "ALB":
            n = Albedo(status=self._status)
        elif type == "SC":
            n = ShadingCoefficient(status=self._status)
        elif type == "CCF":
            n = CloudCoverFraction(status=self._status)
        else:
            n = NotDefined(status=self._status)
        self._lst.insert(index, n)
        self._status.modified()
        return n

    @property
    def Weather_Parameters_List(self):
        return self.lst

    @property
    def default(self):
        return self._default.copy()

    def default_for_type(self, type):
        for wp_default in self.default:
            if wp_default.type == type:
                return wp_default
        return None
