from pydantic import BaseModel
from typing import List, Dict, Any, Optional

from app.utils.constants import PAGE_SIZE
from app.utils.messages import Message


class BaseResponseModel(BaseModel):
    message: str


class ListResponseModel(BaseResponseModel):
    entities: List[Any]
    message: Optional[str] = None
    page_size: Optional[int] = None
    total_count: Optional[int] = None


class TargetListResponseModel(ListResponseModel):
    assigned_sale_target: Optional[float] = 0
    assigned_recovery_target: Optional[float] = 0


class LedgerListResponseModel(ListResponseModel):
    total_balance: Optional[float] = 0


class CustomLedgerListResponseModel(BaseResponseModel):
    entity: Dict[str, Any]
    page_size: Optional[int] = None
    total_count: Optional[int] = None


class ObjectResponseModel(BaseResponseModel):
    entity: Any


class LoginResponseModel(BaseResponseModel):
    user: Optional[Any] = None
    access_token: Optional[str] = None


class ErrorResponseModel(BaseResponseModel):
    errors: List[str]


class Response:
    @staticmethod
    def get_list(collection: List[Any], total: int = 0, page_size: int = PAGE_SIZE, entities_only: bool = False,
                 name="Entities") -> ListResponseModel:
        return ListResponseModel(
            message=Message.Success.OBJECT_GET % name,
            entities=collection,
            page_size=page_size if not entities_only else None,
            total_count=total if not entities_only else None
        )

    @staticmethod
    def get_target_list(collection: List[Any], total: int = 0, sale_target: float = 0, recovery_target: float = 0,
                        entities_only: bool = False) -> TargetListResponseModel:
        return TargetListResponseModel(
            message=Message.Success.OBJECT_GET % "Entities",
            entities=collection,
            page_size=len(collection) if not entities_only else None,
            total_count=total if not entities_only else None,
            assigned_sale_target=sale_target,
            assigned_recovery_target=recovery_target
        )

    @staticmethod
    def get_ledger_list(collection: List[Any], total: int = 0, total_balance: float = 0) -> LedgerListResponseModel:
        return LedgerListResponseModel(
            message=Message.Success.OBJECT_GET % "Ledger",
            entities=collection,
            page_size=len(collection),
            total_count=total,
            total_balance=total_balance
        )

    # @staticmethod
    # def get_custom_ledger_list(collection: List[Any], total: int = 0,
    #                            additional_fields: Dict[str, Any] = None) -> CustomLedgerListResponseModel:
    #     entity = {"ledger": collection}
    #     if additional_fields:
    #         entity.update(additional_fields)
    #     return (CustomLedgerListResponseModel(
    #         message=Message.Success.OBJECT_GET % "Ledger",
    #         entity=entity,
    #         page_size=len(collection),
    #         total_count=total
    #     )

    @staticmethod
    def login_user(
            message: str = '',
            user: Optional[Any] = None,
            access_token: Optional[str] = None
    ) -> LoginResponseModel:
        return LoginResponseModel(
            message=message if message else Message.Success.LOGIN_SUCCESS % user.get('name') if user.get(
                "name") else "User",
            user=user,
            access_token=access_token
        )

    @staticmethod
    def post(obj: Any = None, name: str = "Object", message: str = None) -> ObjectResponseModel:
        return ObjectResponseModel(
            message=message if message else Message.Success.OBJECT_SAVED % name,
            entity=obj
        )

    @staticmethod
    def get(obj: Any = None, name: str = "Object", message: str = None) -> ObjectResponseModel:
        return ObjectResponseModel(
            message=message if message else Message.Success.OBJECT_GET % name,
            entity=obj
        )

    @staticmethod
    def list(entities: Any = None,
             name: str = "Object",
             message: str = None,
             page_size: Optional[int] = 10,
             total_count: Optional[int] = None) -> ListResponseModel:
        return ListResponseModel(
            message=message if message else Message.Success.OBJECT_GET % name,
            entities=entities,
            page_size=page_size,
            total_count=total_count,
        )

    @staticmethod
    def success(message: str = Message.Success.REQUEST_SUCCESS) -> BaseResponseModel:
        return BaseResponseModel(
            message=message
        )

    @staticmethod
    def put(obj: Any = None, name: str = "Object") -> ObjectResponseModel:
        return ObjectResponseModel(
            message=Message.Success.OBJECT_UPDATED % name,
            entity=obj if obj is not None else None
        )

    @staticmethod
    def delete(name: str = "Object") -> BaseResponseModel:
        return BaseResponseModel(
            message=Message.Success.OBJECT_DELETED % name,
        )

    @staticmethod
    def cancel(name: str = "Object") -> BaseResponseModel:
        return BaseResponseModel(
            message=Message.Success.OBJECT_CANCELLED % name,
        )

    @staticmethod
    def error(message: str = Message.Error.INTERNAL_SERVER_ERROR, errors: List[str] = None) -> ErrorResponseModel:
        return ErrorResponseModel(
            message=message,
            errors=errors or [Message.Error.INTERNAL_SERVER_ERROR]
        )
