from typing import List

from pydantic import (
    BaseModel,
    ValidationError,
    StrictInt,
    StrictStr,
    validator,
    StrictBool,
)
from werkzeug.datastructures import FileStorage

from app.extensions.utils.enum.image_enum import ImageFormatEnum, ImageSizeEnum
from app.extensions.utils.log_helper import logger_
from core.domains.admin.dto.admin_dto import (
    CreateAdminPostDto,
    UpdateAdminPostDto,
    DeleteAdminPostDto,
    GetAdminPostDto,
    GetAdminFeedsDto,
    DeleteAdminCommentDto,
    GetAdminUserDto,
    DeleteAdminUserDto,
    GetAdminCSDto,
    UpdateAdminCSDto,
)
from core.exceptions import InvalidRequestException

logger = logger_.getLogger(__name__)


class CreateAdminPostSchema(BaseModel):
    user_id: StrictInt
    post_category_id: StrictInt
    title: StrictStr
    body: StrictStr
    files: List


class CreateAdminPostRequest:
    def __init__(
        self, user_id, title, body, files,
    ):
        self.user_id = int(user_id) if user_id else None
        self.post_category_id = 100
        self.title = title
        self.body = body
        self.files = files

    def validate_request_and_make_dto(self):
        try:
            schema = CreateAdminPostSchema(
                user_id=self.user_id,
                post_category_id=self.post_category_id,
                title=self.title,
                body=self.body,
                files=self.files,
            ).dict()
            return CreateAdminPostDto(**schema)
        except ValidationError as e:
            logger.error(
                f"[CreateAdminPostRequest][validate_request_and_make_dto] error : {e}"
            )
            raise InvalidRequestException(message=e.errors())


class UpdateAdminPostSchema(BaseModel):
    post_id: StrictInt
    user_id: StrictInt
    post_category_id: StrictInt
    body: StrictStr
    title: StrictStr
    delete_files: List


class ImageListSchema(BaseModel):
    files: List

    @validator("files")
    def image_validation(cls, files: List):
        try:
            for file in files:
                extension: str = file.filename.split(".")[1]
                if extension not in ImageFormatEnum.list():
                    raise ValidationError(
                        "allowed image extension format: jpg, jpeg, png"
                    )

                bytes_size = ImageListSchema.get_bytes_size(cls=cls, file=file)

                if bytes_size > ImageSizeEnum.ALLOWED_MAX_SIZE_BYTES.value:
                    raise ValidationError(
                        f"file size over {ImageSizeEnum.ALLOWED_MAX_SIZE_MEGABYTES.value}MB"
                    )

        except IndexError:
            raise ValidationError("not found extension format")
        return files

    def get_bytes_size(cls, file: FileStorage):
        return len(file.read())


class UpdateAdminPostRequest:
    def __init__(
        self, user_id, post_id, post_category_id, body, title, files, delete_files
    ):
        self.post_id = int(post_id) if post_id else None
        self.user_id = int(user_id) if user_id else None
        self.post_category_id = int(post_category_id) if post_category_id else None
        self.body = body
        self.title = title
        self.files = files
        self.delete_files = delete_files

    def validate_request_and_make_dto(self):
        try:
            schema = UpdateAdminPostSchema(
                post_id=self.post_id,
                user_id=self.user_id,
                post_category_id=self.post_category_id,
                body=self.body,
                title=self.title,
                delete_files=self.delete_files,
            ).dict()

            file_list_schema = ImageListSchema(files=self.files)

            schema.update(file_list_schema.dict())
            return UpdateAdminPostDto(**schema)
        except ValidationError as e:
            logger.error(
                f"[UpdateAdminPostRequest][validate_request_and_make_dto] error : {e}"
            )
            raise InvalidRequestException(message=e.errors())


class DeleteAdminPostSchema(BaseModel):
    post_id: StrictInt
    user_id: StrictInt


class DeleteAdminPostRequest:
    def __init__(self, user_id, post_id):
        self.post_id = int(post_id) if post_id else None
        self.user_id = int(user_id) if user_id else None

    def validate_request_and_make_dto(self):
        try:
            schema = DeleteAdminPostSchema(
                post_id=self.post_id, user_id=self.user_id,
            ).dict()
            return DeleteAdminPostDto(**schema)
        except ValidationError as e:
            logger.error(
                f"[DeleteAdminPostRequest][validate_request_and_make_dto] error : {e}"
            )
            raise InvalidRequestException(message=e.errors())


class GetAdminPostSchema(BaseModel):
    post_id: StrictInt
    user_id: StrictInt


class GetAdminPostRequest:
    def __init__(self, user_id, post_id):
        self.post_id = int(post_id) if post_id else None
        self.user_id = int(user_id) if user_id else None

    def validate_request_and_make_dto(self):
        try:
            schema = GetAdminPostSchema(
                post_id=self.post_id, user_id=self.user_id,
            ).dict()
            return GetAdminPostDto(**schema)
        except ValidationError as e:
            logger.error(
                f"[GetAdminPostRequest][validate_request_and_make_dto] error : {e}"
            )
            raise InvalidRequestException(message=e.errors())


class GetAdminFeedsSchema(BaseModel):
    user_id: StrictInt
    post_category_id: StrictInt
    page_no: StrictInt | None
    target_user_id: StrictInt | None


class GetAdminFeedsRequest:
    def __init__(self, user_id, post_category_id, page_no, target_user_id):
        self.user_id = int(user_id) if user_id else None
        self.post_category_id = int(post_category_id) if post_category_id else None
        self.page_no = int(page_no) if page_no else None
        self.target_user_id = int(target_user_id) if target_user_id else None

    def validate_request_and_make_dto(self):
        try:
            schema = GetAdminFeedsSchema(
                user_id=self.user_id,
                post_category_id=self.post_category_id,
                page_no=self.page_no,
                target_user_id=self.target_user_id,
            ).dict()
            return GetAdminFeedsDto(**schema)
        except ValidationError as e:
            logger.error(
                f"[GetAdminFeedsRequest][validate_request_and_make_dto] error : {e}"
            )
            raise InvalidRequestException(message=e.errors())


class DeleteAdminCommentSchema(BaseModel):
    comment_id: StrictInt
    user_id: StrictInt


class DeleteAdminCommentRequest:
    def __init__(self, user_id, comment_id):
        self.user_id = int(user_id) if user_id else None
        self.comment_id = int(comment_id) if comment_id else None

    def validate_request_and_make_dto(self):
        try:
            schema = DeleteAdminCommentSchema(
                user_id=self.user_id, comment_id=self.comment_id
            ).dict()
            return DeleteAdminCommentDto(**schema)
        except ValidationError as e:
            logger.error(
                f"[DeleteAdminCommentRequest][validate_request_and_make_dto] error : {e}"
            )
            raise InvalidRequestException(message=e.errors())


class GetAdminUserSchema(BaseModel):
    target_user_id: StrictInt | None
    nickname: StrictStr | None
    page_no: StrictInt | None
    user_id: StrictInt


class GetAdminUserRequest:
    def __init__(self, user_id, target_user_id, nickname, page_no):
        self.user_id = int(user_id) if user_id else None
        self.target_user_id = int(target_user_id) if target_user_id else None
        self.page_no = int(page_no) if page_no else None
        self.nickname = nickname if nickname else None

    def validate_request_and_make_dto(self):
        try:
            schema = GetAdminUserSchema(
                target_user_id=self.target_user_id,
                nickname=self.nickname,
                user_id=self.user_id,
                page_no=self.page_no,
            ).dict()
            return GetAdminUserDto(**schema)
        except ValidationError as e:
            logger.error(
                f"[GetAdminUserRequest][validate_request_and_make_dto] error : {e}"
            )
            raise InvalidRequestException(message=e.errors())


class DeleteAdminUserSchema(BaseModel):
    user_id: StrictInt
    target_user_id: StrictInt


class DeleteAdminUserRequest:
    def __init__(self, user_id, target_user_id):
        self.user_id = int(user_id) if user_id else None
        self.target_user_id = int(target_user_id) if target_user_id else None

    def validate_request_and_make_dto(self):
        try:
            schema = DeleteAdminUserSchema(
                user_id=self.user_id, target_user_id=self.target_user_id
            ).dict()
            return DeleteAdminUserDto(**schema)
        except ValidationError as e:
            logger.error(
                f"[DeleteAdminUserRequest][validate_request_and_make_dto] error : {e}"
            )
            raise InvalidRequestException(message=e.errors())


class GetAdminCSSchema(BaseModel):
    user_id: StrictInt
    is_solved: StrictBool
    email: StrictStr | None
    page_no: StrictInt | None


class GetAdminCSRequest:
    def __init__(self, user_id, is_solved, email, page_no):
        self.user_id = int(user_id) if user_id else None
        self.is_solved = is_solved
        self.email = email
        self.page_no = int(page_no) if page_no else None

    def validate_request_and_make_dto(self):
        try:
            schema = GetAdminCSSchema(
                user_id=self.user_id,
                is_solved=self.is_solved,
                email=self.email,
                page_no=self.page_no,
            ).dict()
            return GetAdminCSDto(**schema)
        except ValidationError as e:
            logger.error(
                f"[GetAdminCSRequest][validate_request_and_make_dto] error : {e}"
            )
            raise InvalidRequestException(message=e.errors())


class UpdateAdminCSSchema(BaseModel):
    user_id: StrictInt
    inquiry_id: StrictInt
    is_solved: StrictBool


class UpdateAdminCSRequest:
    def __init__(self, user_id, inquiry_id, is_solved):
        self.user_id = int(user_id) if user_id else None
        self.inquiry_id = int(inquiry_id) if inquiry_id else None
        self.is_solved = is_solved

    def validate_request_and_make_dto(self):
        try:
            schema = UpdateAdminCSSchema(
                user_id=self.user_id,
                inquiry_id=self.inquiry_id,
                is_solved=self.is_solved,
            ).dict()
            return UpdateAdminCSDto(**schema)
        except ValidationError as e:
            logger.error(
                f"[UpdateAdminCSRequest][validate_request_and_make_dto] error : {e}"
            )
            raise InvalidRequestException(message=e.errors())
