from typing import Any, Union
from fastapi import status
from fastapi.responses import JSONResponse

from databases.sql_models.response_model import AlchemyResponse


class AlchemyJsonResponse:
    status_code: status
    message: str
    result: AlchemyResponse
    completed: bool
    filter_attributes: Any = None
    response_model: Any = None
    cls_object: Any = None

    @staticmethod
    def get_total_count(cls_object, filter_attributes):
        total_page_number = 1
        count_to_use = cls_object.total_count / int(filter_attributes.size)
        if cls_object.total_count > int(filter_attributes.size):
            if isinstance(count_to_use, int):
                total_page_number = round(count_to_use, 0)
            elif isinstance(count_to_use, float):
                total_page_number = round(count_to_use, 0) + 1
        return total_page_number

    def __new__(
        cls,
        message: str,
        status_code: str = "HTTP_200_OK",
        result: Union[Any, list] = None,
        completed: bool = True,
        response_model: Any = None,
        cls_object: Any = None,
        filter_attributes: Any = None,
    ):
        cls.status_code = getattr(status, status_code, "HTTP_200_OK")
        cls.message = message
        cls.result = result
        cls.completed = completed
        cls.response_model = response_model

        pagination_dict = {
            "size/total_count": [10, 10],
            "page/total_page": [1, 1],
            "order_field": "id",
            "order_type": "asc",
        }
        if filter_attributes:
            total_page_number = cls.get_total_count(cls_object, filter_attributes)
            pagination_dict = {
                "size/total_count": [filter_attributes.size, cls_object.total_count],
                "page/total_page": [filter_attributes.page, total_page_number],
                "order_field": filter_attributes.order_field,
                "order_type": filter_attributes.order_type,
            }

        if isinstance(cls.result, dict) or isinstance(cls.result, list):
            return JSONResponse(
                status_code=cls.status_code,
                content=dict(
                    total_count=len(cls.result),
                    count=len(cls.result),
                    pagination=pagination_dict,
                    completed=cls.completed,
                    message=cls.message,
                    data=cls.result,
                ),
            )

        first_item = getattr(cls.result, "data", None)
        if not first_item:
            return JSONResponse(
                status_code=cls.status_code,
                content=dict(
                    total_count=0,
                    count=0,
                    pagination=pagination_dict,
                    completed=cls.completed,
                    message=cls.message,
                    data=[],
                ),
            )

        if cls.result.first:
            return JSONResponse(
                status_code=cls.status_code,
                content=dict(
                    total_count=1,
                    count=1,
                    pagination=pagination_dict,
                    completed=cls.completed,
                    message=cls.message,
                    data=cls.result.data.get_dict(),
                ),
            )

        if not cls.result.get(1).filter_attr and isinstance(cls.result.data, list):
            counts = cls.result.count
            return JSONResponse(
                status_code=cls.status_code,
                content=dict(
                    total_count=counts,
                    count=counts,
                    pagination=pagination_dict,
                    completed=cls.completed,
                    message=cls.message,
                    data=[result_data.get_dict() for result_data in cls.result.data],
                ),
            )

        # filter_model = cls.result.get(1).filter_attr
        total_count = cls.result.get(1).query.limit(None).offset(None).count()
        total_page_number = cls.get_total_count(cls_object, filter_attributes)
        pagination_dict = {
            "size/total_count": [filter_attributes.size, cls_object.total_count],
            "page/total_page": [filter_attributes.page, total_page_number],
            "order_field": filter_attributes.order_field,
            "order_type": filter_attributes.order_type,
        }
        include_joins = dict(
            include_joins=(
                filter_attributes.include_joins
                if filter_attributes.include_joins
                else []
            )
        )
        data = []
        for data_object in cls.result.data:
            data_dict = data_object.get_dict(include_joins=include_joins)
            if cls.response_model:
                data_dict = cls.response_model(
                    **data_object.get_dict(include_joins=include_joins)
                ).dump()
            data.append(data_dict)
        return JSONResponse(
            status_code=cls.status_code,
            content=dict(
                total_count=total_count or 1,
                count=cls.result.count,
                pagination=pagination_dict,
                message=cls.message,
                completed=cls.completed,
                data=data,
            ),
        )
