#!/usr/bin/python3

LICENSE = """
Copyright (c) 2023 NIBIO <http://www.nibio.no/>. 

This file is part of VIPSCore-Python-Common.
VIPSCore-Python-Common is free software: you can redistribute it and/or modify
it under the terms of the NIBIO Open Source License as published by 
NIBIO, either version 1 of the License, or (at your option) any
later version.
 
VIPSCore-Python-Common 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
NIBIO Open Source License for more details.

You should have received a copy of the NIBIO Open Source License
along with VIPSCore-Python-Common.  If not, see <http://www.nibio.no/licenses/>.
"""

from .vips_model import VIPSModel
from .entities import Result, ModelConfiguration, WeatherObservation
from .data_utils import *
import numpy as np

class ReferenceModel(VIPSModel):
    """
        A reference implementation of the VIPSModel abstract class. Showcasing core functionality
        and best practices
    """

    MODEL_ID        = "REFERENCEM"
    COPYRIGHT       = "(c) 2023 NIBIO"

    THRESHOLD_LOW = 100.0
    THRESHOLD_MEDIUM = 300.0
    THRESHOLD_HIGH = 500.0
 
    def set_configuration(self, model_configuration: ModelConfiguration):
        if not isinstance(model_configuration, ModelConfiguration):
            raise ValueError("%s is not a ModelConfiguration object" % model_configuration)
        if model_configuration.model_id != ReferenceModel.MODEL_ID:
            raise ValueError("%s is not the correct model ID!" % model_configuration.model_id)
        
        # Input data check
        self.sowing_date = model_configuration.get_config_parameter_as_date("sowingDate")
        self.timezone = model_configuration.get_config_parameter_as_timezone("timeZone")
        # Weather data is turned into Pandas dataframe
        self.df = get_dataframe_from_weather_observations(
                get_weather_observations_from_json_list(
                    model_configuration.config_parameters["observations"]
                    ),
                self.timezone
            )

    

    def determine_warning_status(self, TMDD: float) -> int:
        """
        Used in get_result as a dataframe operation. Determines the warning status
        based on the model thresholds
        """
        if TMDD < ReferenceModel.THRESHOLD_MEDIUM:
            return  Result.WARNING_STATUS_NO_WARNING
        if TMDD < ReferenceModel.THRESHOLD_HIGH:
            return Result.WARNING_STATUS_MINOR_RISK
        else:
            return Result.WARNING_STATUS_HIGH_RISK

        
    
    def get_result(self) -> list[Result]:
        """Get the results as a list of Result objects (TODO ref)"""
        
        # Calculate day degrees from sowingDate and as far as weather data goes
        # Adjusting for base temperature
        self.df["TMContrib"] = self.df["TM"].apply(get_temp_adjusted_for_base, args=(5,))
        # Aggregating the day degrees
        self.df["TMDD"] = self.df["TMContrib"].cumsum()
        # Adding the thresholds to the data frame
        self.df["THRESHOLD_LOW"] = ReferenceModel.THRESHOLD_LOW
        self.df["THRESHOLD_MEDIUM"] = ReferenceModel.THRESHOLD_MEDIUM
        self.df["THRESHOLD_HIGH"] = ReferenceModel.THRESHOLD_HIGH
        # For each day: check accumulated day-degrees and decide warning status
        self.df["WARNING_STATUS"] = self.df["TMDD"].apply(self.determine_warning_status)
        #print(self.df)
        result = get_result_list_from_dataframe(self.df)
        #print(result)
        return result
        

    @property
    def model_id(self) -> str:
        """10-character ID of the model. Must be unique (at least in the current system)"""
        return ReferenceModel.MODEL_ID

    
    @property
    def license(self) -> str:
        """Returns the license for this piece of software"""
        return LICENSE

    @property
    def copyright(self) -> str:
        """Name of person/organization that holds the copyright, and contact information"""
        return ReferenceModel.COPYRIGHT
    
    @property
    def sample_config(self) -> dict:
        """A sample configuration in JSON format (TODO check relation with Dict)"""
        return """
        {
	model_id:'REFERENCEM',
	config_parameters: {
		'sowingDate': '2022-03-01', 
		'observations': [
			{'timeMeasured': '2015-03-01T00:00:00+01:00', 'elementMeasurementTypeId': 'TM', 'logIntervalId': '2', 'value': '1.41025'}, 
			{'timeMeasured': '2015-03-02T00:00:00+01:00', 'elementMeasurementTypeId': 'TM', 'logIntervalId': '2', 'value': '2.87608333333333'}, 
			{'timeMeasured': '2015-03-03T00:00:00+01:00', 'elementMeasurementTypeId': 'TM', 'logIntervalId': '2', 'value': '1.00854166666667'}, 
			{'timeMeasured': '2015-03-04T00:00:00+01:00', 'elementMeasurementTypeId': 'TM', 'logIntervalId': '2', 'value': '-1.44675'}
		]
	}
}
        """

    def get_model_name(self, language = VIPSModel.default_language) -> str:
        """Returns the model name in the specified language (<a href="http://www.loc.gov/standards/iso639-2/php/English_list.php">ISO-639-2</a>)"""
        return "Reference Model"     

    def get_model_description(self, language = VIPSModel.default_language) -> str:
        """Returns the model description in the specified language (<a href="http://www.loc.gov/standards/iso639-2/php/English_list.php">ISO-639-2</a>)"""
        return """
        The model is a reference model for developers, showcasing best practices and functionalities of a model.
        It's a simple day degree model for an imagined pest, and when thresholds are passed, the warning status progresses.
        """

    def get_warning_status_interpretation(self, language = VIPSModel.default_language) -> str:
        """How to interpret the warning status (red-yellow-green, what does it mean?) in the specified language (<a href="http://www.loc.gov/standards/iso639-2/php/English_list.php">ISO-639-2</a>)"""
        return """
        Gray   status (warning status == 0): Warning not applicable
        Blue   status (warning status == 1): Missing data
        Green  status (warning status == 2): No risk. Sleep well
        Yellow status (warning status == 3): The day-degree hreshold for medium risk has been passed. Be on the alert, inspect your field
        Red status    (warning status == 4): The day-degree threshold for high risk has been passed. When the going gets tough, the tough get going
        """

    def get_model_usage(self, language = VIPSModel.default_language) -> str:
        """Technical manual for this model, in the specified language  (<a href="http://www.loc.gov/standards/iso639-2/php/English_list.php">ISO-639-2</a>)"""
        return "TODO"