from datetime import date
from typing import Callable, Optional
from datetime import datetime
# import dapla_suv_tools._internals.client_apis.skjema_api as skjema_api
from dapla_suv_tools._internals.client_apis import periode_api
from dapla_suv_tools._internals.util.help_helper import HelpAssistant
from dapla_suv_tools._internals.util.operation_result import OperationResult
from dapla_suv_tools._internals.util import constants
from dapla_suv_tools.pagination import PaginationInfo


class SuvClient:
    suppress_exceptions: bool
    operations_log: list
    help_assistant: HelpAssistant

    from dapla_suv_tools._internals.client_apis.skjema_api import (
        get_skjema_by_id,
        get_skjema_by_ra_nummer,
        create_skjema,
        delete_skjema
    )

    from dapla_suv_tools._internals.client_apis.periode_api import (
        get_periode_by_id,
        get_perioder_by_skjema_id,
        create_periode,
        delete_periode
    )

    def __init__(self, suppress_exceptions: bool = False):
        self.suppress_exceptions = suppress_exceptions
        self.operations_log = []
        self._build_help_cache()

    def logs(self, threshold: str | None = None, results: int = 0) -> list:

        if not threshold or threshold not in constants.LOG_LEVELS:
            threshold = constants.LOG_INFO

        log = self._filter_logs(threshold=threshold)

        if results > 0:
            return log[-results:]

        return log

    def help(self, function: Optional[Callable] = None) -> str:
        if function is None:
            return self.__doc__
        doc = self.help_assistant.get_function_help_entry(function.__name__)

        if doc is not None:
            return doc

        return f"No help entry for '{function.__name__}' exists."

    def _build_help_cache(self):
        self.help_assistant = HelpAssistant()
        self.help_assistant.register_function(self.get_skjema_by_id)
        self.help_assistant.register_function(self.get_skjema_by_ra_nummer)
        self.help_assistant.register_function(self.create_skjema)
        self.help_assistant.register_function(self.delete_skjema)
        self.help_assistant.register_function(self.get_periode_by_id)
        self.help_assistant.register_function(self.get_perioder_by_skjema_id)
        self.help_assistant.register_function(self.create_periode)
        self.help_assistant.register_function(self.delete_periode)

    def flush_logs(self):
        self.operations_log = []

    # Skjema

    # def get_skjema_by_id(self, *, skjema_id: int) -> dict:
    #     result = skjema_api.get_skjema_by_id(self, skjema_id=skjema_id)
    #     return self._process_result(result=result)

    # def get_skjema_by_ra_nummer(
    #         self,
    #         *,
    #         ra_nummer: str,
    #         latest_only: bool = False,
    #         pagination_info: PaginationInfo = None) -> dict:
    #     result = skjema_api.get_skjema_by_ra_nummer(ra_nummer=ra_nummer, latest_only=latest_only, paging=pagination_info)
    #     return self._process_result(result=result)

    # def create_skjema(
    #         self,
    #         *,
    #         ra_nummer: str,
    #         versjon: int,
    #         undersokelse_nr: str,
    #         gyldig_fra: date,
    #         datamodell: str | None = None,
    #         beskrivelse: str | None = None,
    #         navn_nb: str | None = None,
    #         navn_nn: str | None = None,
    #         navn_en: str | None = None,
    #         infoside: str | None = None,
    #         eier: str | None = None,
    #         kun_sky: bool = False,
    #         gyldig_til: date | None = None,
    # ) -> dict:
    #     fwd_args = {k: v for k,v in locals().items() if k not in {"self", "*"}}
    #
    #     result = skjema_api.create_skjema(**fwd_args)
    #     return self._process_result(result=result)
    #
    # def delete_skjema(self, skjema_id: int) -> dict:
    #     result = skjema_api.delete_skjema(skjema_id=skjema_id)
    #     return self._process_result(result=result)

    # Periode
    #
    # def get_periode_by_id(self, *, periode_id: int) -> dict:
    #     result = periode_api.get_periode_by_id(periode_id=periode_id)
    #     return self._process_result(result=result)

    # def get_perioder_by_skjema_id(self, *, skjema_id: int) -> dict:
    #     result = periode_api.get_perioder_by_skjema_id(skjema_id=skjema_id)
    #     return self._process_result(result=result)

    # def create_periode(
    #         self,
    #         *,
    #         skjema_id: int,
    #         periode_type: str | None = None,
    #         periode_nr: int | None = None,
    #         periode_aar: int | None = None,
    #         periode_dato: date | None = None,
    #         delreg_nr: int | None = None,
    #         enhet_type: str | None = None,
    #         vis_oppgavebyrde: str | None = "N",
    #         vis_brukeropplevelse: str | None = "N",
    #         altinn_tilgjengelig: date | None = None,
    #         altinn_svarfrist: date | None = None,
    # ) -> dict:
    #     fwd_args = {k: v for k, v in locals().items() if k not in {"self", "*"}}
    #     result = periode_api.create_periode(**fwd_args)
    #     return self._process_result(result=result)
    #
    # def delete_periode(self, *, periode_id: int) -> dict:
    #     result = periode_api.delete_periode(periode_id=periode_id)
    #     return self._process_result(result=result)

    def _process_result(self, result: OperationResult) -> dict:
        self.operations_log.append(result.operation_log)
        if result.result == constants.OPERATION_OK:
            return result.result_json

        if result.result == constants.OPERATION_ERROR:
            if self.suppress_exceptions:
                return result.result_json
            errors = result.result_json["errors"]
            raise errors[len(errors) - 1]["exception"]

        return {"result": "Undefined result.  This shouldn't happen."}

    def _filter_logs(self, threshold: str) -> list:
        limit = constants.LOG_LEVELS.index(threshold)

        filtered = []

        for log_entry in self.operations_log:
            logs = log_entry["logs"]
            if len(logs) == 0:
                continue
            for entry in logs:
                if constants.LOG_LEVELS.index(entry["level"]) < limit:
                    continue
                filtered.append(entry)

        return sorted(filtered, key=lambda x: x["time"])
