#!/usr/bin/env python3
# a small http client that query mon eco watt signal


import json
import enum
import pytz
import requests
import argparse
import datetime
import dataclasses
from typing import Optional, List


class Values(enum.Enum):
    """
    Values of the signal
    """
    UNKNOWN=0
    GOOD=1
    MEDIUM=2
    CRITICAL=3


@dataclasses.dataclass
class Status:
    """
    Human readable struct for analysis
    """
    date: datetime.datetime
    value: int
    label: str


class Resources:
    """
    Some resources
    """
    TOKEN_URL = "https://digital.iservices.rte-france.com/token/oauth"
    SIGNALS_URL = "https://digital.iservices.rte-france.com/open_api/ecowatt/v4/signals"
    SANDBOX_URL = "https://digital.iservices.rte-france.com/open_api/ecowatt/v4/sandbox/signals"
    TOKEN_SECRET = "" # from your API dashboard


class MonEcoWatt:
    def __init__(self):
        pass

    def get_token(self) -> Optional[str]:
        """
        Get a token from your API account
        """
        headers = {
            "Content-Type": "application/x-www-urlencoded",
            "Authorization": f"Basic {Resources.TOKEN_SECRET}",
        }

        try:
            res = requests.post(Resources.TOKEN_URL, headers=headers).json()
            token = res.get("access_token", None)
        except Exception as e:
            print(str(e))
            return None
        else:
            return token

    def get_ecowatt_status(self, token:str) -> Optional[dict]:
        """
        Get the current ecowatt status
        """
        if token is None:
            print("Token is empty")
            return None

        headers = {
            "Content-Type": "application/json",
            "Authorization": f"Bearer {token}",
        }

        try:
            res = requests.get(Resources.SIGNALS_URL, headers=headers)
        except Exception as e:
            print(str(e))
            return None
        finally:
            pass

        status_code = res.status_code
        if status_code == 429:
            response_headers = res.headers
            print(f'Rate exceeded, retry after {response_headers["Retry-After"]} seconds')
            return None
        elif status_code == 200:
            try:
                json = res.json()
            except Exception as e:
                print(str(e))
                return None
            else:
                return json
        else:
            print(f"Status code: {status_code}")
            return None

    def generate_calendar(self, status:dict) -> List[Status]:
        """
        Given the JSON response, generate a calendar
        """
        label_table = ["unknown", "good", "medium", "critical"]

        predictions = []
        for day in status["signals"]:
            date = datetime.datetime.strptime(day["jour"], "%Y-%m-%dT%H:%M:%S%z")
            for value in day["values"]:

                sig_date = date + datetime.timedelta(hours=value["pas"])
                sig_value = value["hvalue"]
                sig_label = label_table[sig_value]

                predictions.append(
                    Status(
                        date=sig_date,
                        value=sig_value,
                        label=sig_label,
                    )
                )
        return predictions

    def check_current_status(self, calendar:List[Status]) -> bool:
        """
        Check the current signal status
        """
        now = datetime.datetime.now(pytz.timezone("Europe/Paris"))

        slot = list(filter(lambda x: x.date > (now - datetime.timedelta(hours=1)), calendar))
        slot = list(filter(lambda x: x.date < now, slot))

        assert len(slot) == 1
        current_slot = slot[0]
        print(current_slot.date)
        print(current_slot.value)
        print(current_slot.label)

        return current_slot.value == Values.GOOD.value

    def run(self):
        token = self.get_token()
        status = self.get_ecowatt_status(token)
        if status:
            calendar = self.generate_calendar(status)
            self.check_current_status(calendar)


if __name__ == "__main__":
    rc = MonEcoWatt()
    rc.run()
