#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from typing import Self, Any
from Interfaces.OpoTestsInterface import OpoTestsInterface
from Models.RouteModel import RouteModel
from re import Match as REMatch
from Models.RequestModel import RequestModel
from Utils.Check import Check
from Utils.Utils import Utils

class RoutesManager:

    def __init__(self:Self, ot:OpoTestsInterface) -> None:
        self.ot:OpoTestsInterface = ot
        self.__routes:tuple[RouteModel] = tuple()

    def start(self:Self) -> None:

        key:str

        for key in ("default_routes_files", "default_routes", "routes_files", "routes"):
            self.add(self.ot.settings.get(key, []), True)

    def add(self:Self, inputs:str|RouteModel|list|tuple, overwrite:bool = False) -> None:

        item:str|RouteModel|list|tuple

        for item in self.ot.load_json_data(inputs, False) or (inputs,):
            if Check.is_string(item):

                route:RouteModel = RouteModel(item)

                if route.done:
                    self.__routes += (route,)
                else:
                    self.add(item, overwrite)

            elif isinstance(item, RouteModel):
                if item.done:
                    self.__routes += (item,)
            elif Check.is_array(item):
                if len(item) == 6 and all(subitem is None or Check.is_string(subitem) for subitem in item):

                    route:RouteModel = RouteModel(item)

                    if route.done:
                        self.__routes += (route,)
                        continue

                for subitem in item:
                    self.add(subitem, overwrite)

    def go(self:Self, request:RequestModel) -> tuple[Any|None, int]:

        route:RouteModel

        for route in self.__routes:
            if route.method == request.method:

                matches:REMatch = route.request.match(request.request)

                if not matches:
                    continue

                request.variables_request = {
                    route.variables[i] : value for i, value in enumerate(matches.groups()[1:])
                }

                if route.path:
                    for index in request.index_files:

                        path:str = request.public_path + '/' + request.request + ('/' + index if index else '')
                        data:bytes|None = self.ot.files.load(path)

                        if data is not None:
                            return (data, {"mime" : self.ot.files.get_mime(path)})
                        
                elif route.controller:

                    data:tuple[Any|None, dict[str, Any|None]]|None = self.ot.controllers.get(
                        route.controller, 
                        route.action, 
                        request
                    )

                    if data is not None:
                        return data
                        
        return (Utils.json_encode({
            "ok" : False, 
            "code" : 404, 
            "message" : "Not found"
        }), {
            "http_code" : 404, 
            "mime" : "application/json"
        })