import fastapi
import fastapi.staticfiles
import fastapi.responses
import pathlib
import os

from . import *
from .requests import *

class server(fastapi.FastAPI):
    def __init__(self, config_file: str) -> None:
        super().__init__()

        location = pathlib.Path(config_file)
        
        self.__resources = config_loader(app_config) \
        .load(location) \
        .resources
        
        self.__static()
        self.__route_product()
        self.__route_users()
        self.__route_reservations()
        self.__route_autoadder()

    @property
    def resources(self) -> app_resources:
        return self.__resources

    @property
    def product_app(self) -> product_app:
        return self.__resources.product_app

    @property
    def users_app(self) -> users_app:
        return self.__resources.users_app

    @property
    def reservation_app(self) -> reservation_app:
        return self.__resources.reservation_app

    @property
    def autoadder_app(self) -> autoadder_app:
        return self.__resources.autoadder_app

    def __static(self) -> None:
        @self.get("/")
        def root() -> str:
            with pathlib.Path("static/core.html").open() as core:
                return fastapi.responses.HTMLResponse(
                    content = core.read(),
                    status_code = 200
                )
    
        app_directory = fastapi.staticfiles.StaticFiles(
            directory = pathlib.Path("static/")
        )

        covers_directory = fastapi.staticfiles.StaticFiles(
            directory = self.resources.config.covers_path 
        )

        self.mount(
            "/app", 
            app_directory, 
            name = "app_frontend"
        )

        self.mount(
            directory_image.server_path(),
            covers_directory,
            name = "covers"
        )

    def __route_autoadder(self) -> None:
        @self.post("/complete/barcode/{barcode}")
        def autoadder_complete_barcode(
            barcode: str,
            request: apikey_request
        ) -> dict:
            body = request.dict()
            body["barcode"] = barcode

            return self.autoadder_app.find(body)

    def __route_reservations(self) -> None:
        @self.post("/reservations/user/email/{email}")
        def reservations_email(
            email: str,
            reservation: reservation_request
        ) -> dict:
            body = reservation.dict()
            body["email"] = email

            return self.reservation_app.get_by_user(body)

        @self.post("/reservations/user/phone_number/{phone_number}")
        def reservations_email(
            phone_number: str,
            reservation: reservation_request
        ) -> dict:
            body = reservation.dict()
            body["phone_number"] = phone_number

            return self.reservation_app.get_by_user(body)

        @self.post("/reservations/product/barcode/{barcode}")
        def reservations_barcode(
            barcode: str,
            reservation: reservation_request
        ) -> dict:
            body = reservation.dict()
            body["target_barcode"] = str(barcode)

            return self.reservation_app.get_by_product(body)

        @self.post("/reservations/product/name/{name}")
        def reservations_name(
            name: str,
            reservation: reservation_request
        ) -> dict:
            body = reservation.dict()
            body["target_name"] = name

            return self.reservation_app.get_by_product(body)

        @self.post("/rent/product/barcode/{barcode}")
        def rent_barcode(
            barcode: str,
            reservation: reservation_request
        ) -> dict:
            body = reservation.dict()
            body["target_barcode"] = str(barcode)
            
            return self.reservation_app.rent_product(body)

        @self.post("/rent/product/name/{name}")
        def rent_name(
            name: str,
            reservation: reservation_request
        ) -> dict:
            body = reservation.dict()
            body["target_name"] = name
            
            return self.reservation_app.rent_product(body)

        @self.post("/give_back/product/barcode/{barcode}")
        def give_back_barcode(
            barcode: str,
            reservation: reservation_request
        ) -> dict:
            body = reservation.dict()
            body["target_barcode"] = str(barcode)

            return self.reservation_app.give_back_product(body)

        @self.post("/give_back/product/name/{name}")
        def give_back_barcode(
            name: str,
            reservation: reservation_request
        ) -> dict:
            body = reservation.dict()
            body["target_name"] = name

            return self.reservation_app.give_back_product(body)

    def __route_product(self) -> None:
        @self.get("/products")
        def products() -> dict:
            return self.product_app.all()

        @self.get("/product/get/barcode/{barcode}")
        def product_get_barcode(barcode: str) -> dict:
            return self.product_app.get_barcode(str(barcode))

        @self.get("/product/get/name/{name}")
        def product_get_name(name: str) -> dict:
            return self.product_app.get_name(name)

        @self.get("/product/search/name/{name}")
        def product_search_name(name: str) -> dict:
            return self.product_app.search_name(name)

        @self.get("/product/search/author/{author}")
        def product_search_author(author: str) -> dict:
            return self.product_app.search_author(author)

        @self.get("/product/check/barcode/{barcode}")
        def product_check_barcode(barcode: str) -> dict:
            return self.product_app.check_barcode(str(barcode))

        @self.get("/product/check/name/{name}")
        def product_check_name(name: str) -> dict:
            return self.product_app.check_name(name)

        @self.post("/product/update/barcode/{barcode}")
        def product_barcode_update(
            barcode: str, 
            product: product_update_request
        ) -> dict:
            body = product.dict()
            body["target_barcode"] = barcode

            return self.product_app.update(body)

        @self.post("/product/update/name/{name}")
        def product_name_update(
            name: str, 
            product: product_update_request
        ) -> dict:
            body = product.dict()
            body["target_name"] = name

            return self.product_app.update(body)

        @self.post("/product/update/image/barcode/{barcode}")
        def product_image_barcode_update(
            barcode: str,
            product_image: product_update_image_request
        ) -> dict:
            body = product_image.dict()
            body["target_barcode"] = barcode

            return self.product_app.update_image(body)
    
        @self.post("/product/update/image/name/{name}")
        def product_image_barcode_update(
            name: str,
            product_image: product_update_image_request
        ) -> dict:
            body = product_image.dict()
            body["target_name"] = name

            return self.product_app.update_image(body)

        @self.delete("/product/barcode/{barcode}")
        def product_barcode_delete(
            barcode: str,
            request: apikey_request
        ) -> dict:
            body = request.dict()
            body["target_barcode"] = barcode

            return self.product_app.delete(body)

        @self.delete("/product/name/{name}")
        def product_name_delete(
            name: str,
            request: apikey_request
        ) -> dict:
            body = request.dict()
            body["target_name"] = name

            return self.product_app.delete(body)

        @self.post("/product/create")
        def product_create(product: product_create_request) -> dict:
            return self.product_app.create(product.dict())

    def __route_users(self) -> None:    
        @self.post("/user/login")
        def user_login(user: user_login_request) -> dict:
            return self.users_app.login(user.nick, user.password)
        
        @self.post("/user")
        def user_get(body: user_get_request) -> dict:
            return self.users_app.get(body.apikey)
        

instance = server(os.environ["config_file"])
