import datetime
import os
import uuid
from http import HTTPStatus
from math import trunc
from typing import List

import inject
from pytz import timezone

from app.extensions.utils.enum.aws_enum import S3PathEnum, CloudFrontEnum, S3BucketEnum
from app.extensions.utils.image_helper import S3Helper
from app.extensions.utils.time_helper import get_server_timestamp
from core.domains.admin.dto.admin_dto import (
    CreateAdminPostAttachmentDto,
    CreateAdminPostDto,
    UpdateAdminPostDto,
    DeleteAdminPostDto,
    GetAdminPostDto,
    GetAdminFeedsDto,
    DeleteAdminCommentDto,
    GetAdminUserDto,
    GetAdminCSDto,
    UpdateAdminCSDto,
)
from core.domains.admin.repository.admin_repository import AdminRepository
from core.domains.community.entity.community_entity import (
    PostEntity,
    PostCategoryEntity,
    FeedEntity,
)
from core.domains.cs.entity.cs_entity import CustomerInquiryEntity
from core.domains.user.entity.user_entity import UserEntity
from core.use_case_output import UseCaseSuccessOutput, UseCaseFailureOutput, FailureType


class AdminBaseUseCase:
    @inject.autoparams()
    def __init__(self, admin_repo: AdminRepository):
        self._admin_repo = admin_repo

    def _upload_post_attachments(
        self, dtos: List[CreateAdminPostAttachmentDto]
    ) -> None:
        for dto in dtos:
            res = S3Helper.upload(
                bucket=S3BucketEnum.PLANTRA_BUCKET_NAME.value,
                file_name=dto.origin_file,
                object_name=dto.object_name,
                extension=dto.extension,
            )

            if res:
                dto.is_upload = True

    def _get_file_split_object(
        self, dto: CreateAdminPostDto | UpdateAdminPostDto, post_id: int
    ) -> List[CreateAdminPostAttachmentDto]:
        results = list()
        for file in dto.files:
            f, extension = os.path.splitext(file.filename)
            uuid_ = str(uuid.uuid4())
            object_name = S3PathEnum.POST_IMGS.value + uuid_ + extension
            path = f"{CloudFrontEnum.PLANTRA_CLOUD_FRONT_DOMAIN.value}/{object_name}"

            create_post_attachment_dto = CreateAdminPostAttachmentDto(
                post_id=post_id,
                uuid=uuid_,
                file_name=f,
                path=path,
                extension=extension,
                object_name=object_name,
                origin_file=file,
                is_upload=False,
            )
            results.append(create_post_attachment_dto)

        return results

    def _check_body_validator(self, body: str) -> dict:
        if not body:
            return dict(status=False, message="empty body")

        if len(body) > 1000:
            return dict(status=False, message="over 1000 char")

        return dict(status=True, message="success")


class CreateAdminPostUseCase(AdminBaseUseCase):
    def execute(
        self, dto: CreateAdminPostDto
    ) -> UseCaseSuccessOutput | UseCaseFailureOutput:
        if not self._admin_repo.is_check_admin_user(user_id=dto.user_id):
            return UseCaseFailureOutput(
                type="not admin permission",
                message=FailureType.UNAUTHORIZED_ERROR,
                code=HTTPStatus.UNAUTHORIZED,
            )

        # body validator
        body_validate_result: dict = self._check_body_validator(body=dto.body)
        if not body_validate_result.get("status"):
            return UseCaseFailureOutput(
                type=body_validate_result.get("message"),
                message=FailureType.INVALID_REQUEST_ERROR,
                code=HTTPStatus.BAD_REQUEST,
            )

        if len(dto.files) > 5:
            return UseCaseFailureOutput(
                type="over 5 picture",
                message=FailureType.INVALID_REQUEST_ERROR,
                code=HTTPStatus.BAD_REQUEST,
            )

        post_id: int = self._admin_repo.create_post(dto=dto)

        if dto.files:
            create_post_attachment_dtos: List[
                CreateAdminPostAttachmentDto
            ] = self._get_file_split_object(dto=dto, post_id=post_id)
            self._upload_post_attachments(dtos=create_post_attachment_dtos)

            for create_post_attachment_dto in create_post_attachment_dtos:
                if not create_post_attachment_dto.is_upload:
                    continue

                self._admin_repo.create_post_attachment(dto=create_post_attachment_dto)

        self._admin_repo.commit_transaction()

        return UseCaseSuccessOutput()


class UpdateAdminPostUseCase(AdminBaseUseCase):
    def execute(
        self, dto: UpdateAdminPostDto
    ) -> UseCaseSuccessOutput | UseCaseFailureOutput:
        if not self._admin_repo.is_check_admin_user(user_id=dto.user_id):
            return UseCaseFailureOutput(
                type="not admin permission",
                message=FailureType.UNAUTHORIZED_ERROR,
                code=HTTPStatus.UNAUTHORIZED,
            )

        # body validator
        body_validate_result: dict = self._check_body_validator(body=dto.body)
        if not body_validate_result.get("status"):
            return UseCaseFailureOutput(
                type=body_validate_result.get("message"),
                message=FailureType.INVALID_REQUEST_ERROR,
                code=HTTPStatus.BAD_REQUEST,
            )

        if len(dto.files) > 5:
            return UseCaseFailureOutput(
                type="over 5 picture",
                message=FailureType.INVALID_REQUEST_ERROR,
                code=HTTPStatus.BAD_REQUEST,
            )

        self._admin_repo.update_post(dto=dto)

        if dto.files:
            create_post_attachment_dtos: List[
                CreateAdminPostAttachmentDto
            ] = self._get_file_split_object(dto=dto, post_id=dto.post_id)
            self._upload_post_attachments(dtos=create_post_attachment_dtos)

            for create_post_attachment_dto in create_post_attachment_dtos:
                if not create_post_attachment_dto.is_upload:
                    continue

                self._admin_repo.create_post_attachment(dto=create_post_attachment_dto)

        if dto.delete_files:
            self._admin_repo.delete_post_attachments(delete_files=dto.delete_files)

        self._admin_repo.commit_transaction()
        return UseCaseSuccessOutput()


class DeleteAdminPostUseCase(AdminBaseUseCase):
    def execute(
        self, dto: DeleteAdminPostDto
    ) -> UseCaseSuccessOutput | UseCaseFailureOutput:
        if not self._admin_repo.is_check_admin_user(user_id=dto.user_id):
            return UseCaseFailureOutput(
                type="not admin permission",
                message=FailureType.UNAUTHORIZED_ERROR,
                code=HTTPStatus.UNAUTHORIZED,
            )

        self._admin_repo.delete_post(post_id=dto.post_id)

        return UseCaseSuccessOutput()


class GetAdminPostUseCase(AdminBaseUseCase):
    def execute(
        self, dto: GetAdminPostDto
    ) -> UseCaseSuccessOutput | UseCaseFailureOutput:
        if not self._admin_repo.is_check_admin_user(user_id=dto.user_id):
            return UseCaseFailureOutput(
                type="not admin permission",
                message=FailureType.UNAUTHORIZED_ERROR,
                code=HTTPStatus.UNAUTHORIZED,
            )

        post: PostEntity | None = self._admin_repo.get_post_by_id(id=dto.post_id)
        post_categories: List[
            PostCategoryEntity
        ] = self._admin_repo.get_post_categories()
        return UseCaseSuccessOutput(
            value=dict(post=post, post_categories=post_categories)
        )


class GetAdminFeedsUseCase(AdminBaseUseCase):
    def execute(
        self, dto: GetAdminFeedsDto
    ) -> UseCaseSuccessOutput | UseCaseFailureOutput:
        if not self._admin_repo.is_check_admin_user(user_id=dto.user_id):
            return UseCaseFailureOutput(
                type="not admin permission",
                message=FailureType.UNAUTHORIZED_ERROR,
                code=HTTPStatus.UNAUTHORIZED,
            )

        feed_entities: List[FeedEntity] | None = self._admin_repo.get_feeds(
            post_category_id=dto.post_category_id,
            user_id=dto.user_id,
            page_no=dto.page_no,
            target_user_id=dto.target_user_id,
        )
        total_post_cnt: int = self._admin_repo.get_total_post(
            post_category_id=dto.post_category_id, target_user_id=dto.target_user_id,
        )

        if feed_entities:
            for feed_entity in feed_entities:
                created_at = feed_entity.created_at.strftime("%Y%m%d %H:%M:%S")
                past = datetime.datetime.strptime(
                    created_at, "%Y%m%d %H:%M:%S"
                ).replace(tzinfo=timezone("Asia/Seoul"))
                today = get_server_timestamp().replace(tzinfo=timezone("Asia/Seoul"))

                diff_time = today - past
                if diff_time.days >= 1:
                    make_diff_day = f"{diff_time.days}일전"

                    diff_month = trunc(diff_time.days / 30)
                    if diff_month > 6:
                        make_diff_day = f"오래전"
                    elif diff_month >= 1:
                        make_diff_day = f"{diff_month}달전"
                else:
                    diff_min = trunc(diff_time.seconds / 60)
                    make_diff_day = f"{diff_min}분전"

                    if diff_min >= 60:
                        diff_hour = trunc(diff_time.seconds / 3600)
                        make_diff_day = f"{diff_hour}시간전"

                feed_entity.create_diff_day = make_diff_day
        cursor = {
            # "previous_id": feed_entities[-1].id if feed_entities else None,
            "current_page_no": dto.page_no,
            "total_post_cnt": total_post_cnt,
        }

        return UseCaseSuccessOutput(value={"data": feed_entities, "cursor": cursor})


class DeleteAdminCommentUseCase(AdminBaseUseCase):
    def execute(
        self, dto: DeleteAdminCommentDto
    ) -> UseCaseSuccessOutput | UseCaseFailureOutput:
        if not self._admin_repo.is_check_admin_user(user_id=dto.user_id):
            return UseCaseFailureOutput(
                type="not admin permission",
                message=FailureType.UNAUTHORIZED_ERROR,
                code=HTTPStatus.UNAUTHORIZED,
            )

        self._admin_repo.delete_comment(comment_id=dto.comment_id)

        return UseCaseSuccessOutput()


class GetAdminUserUseCase(AdminBaseUseCase):
    def execute(
        self, dto: GetAdminUserDto
    ) -> UseCaseSuccessOutput | UseCaseFailureOutput:
        if not self._admin_repo.is_check_admin_user(user_id=dto.user_id):
            return UseCaseFailureOutput(
                type="not admin permission",
                message=FailureType.UNAUTHORIZED_ERROR,
                code=HTTPStatus.UNAUTHORIZED,
            )

        users: List[UserEntity] | None = self._admin_repo.get_user(
            target_user_id=dto.target_user_id,
            nickname=dto.nickname,
            page_no=dto.page_no,
        )
        total_user_cnt: int = self._admin_repo.get_total_user(
            target_user_id=dto.target_user_id, nickname=dto.nickname,
        )
        cursor = {
            # "previous_id": users[-1].id if users else None,
            "current_page_no": dto.page_no,
            "total_user_cnt": total_user_cnt,
        }

        return UseCaseSuccessOutput(value={"data": users, "cursor": cursor})


class DeleteAdminUserUseCase(AdminBaseUseCase):
    def execute(
        self, dto: GetAdminUserDto
    ) -> UseCaseSuccessOutput | UseCaseFailureOutput:
        if not self._admin_repo.is_check_admin_user(user_id=dto.user_id):
            return UseCaseFailureOutput(
                type="not admin permission",
                message=FailureType.UNAUTHORIZED_ERROR,
                code=HTTPStatus.UNAUTHORIZED,
            )

        self._admin_repo.delete_user(target_user_id=dto.target_user_id)
        return UseCaseSuccessOutput()


class GetAdminCSUseCase(AdminBaseUseCase):
    def execute(
        self, dto: GetAdminCSDto
    ) -> UseCaseSuccessOutput | UseCaseFailureOutput:
        if not self._admin_repo.is_check_admin_user(user_id=dto.user_id):
            return UseCaseFailureOutput(
                type="not admin permission",
                message=FailureType.UNAUTHORIZED_ERROR,
                code=HTTPStatus.UNAUTHORIZED,
            )

        cs_entities: List[CustomerInquiryEntity] | None = self._admin_repo.get_cs(
            is_solved=dto.is_solved, email=dto.email, page_no=dto.page_no
        )
        total_cs_cnt: int = self._admin_repo.get_total_cs(
            is_solved=dto.is_solved, email=dto.email,
        )

        if cs_entities:
            for cs_entitiy in cs_entities:
                created_at = cs_entitiy.created_at.strftime("%Y%m%d %H:%M:%S")
                past = datetime.datetime.strptime(
                    created_at, "%Y%m%d %H:%M:%S"
                ).replace(tzinfo=timezone("Asia/Seoul"))
                today = get_server_timestamp().replace(tzinfo=timezone("Asia/Seoul"))

                diff_time = today - past
                if diff_time.days >= 1:
                    make_diff_day = f"{diff_time.days}일전"

                    diff_month = trunc(diff_time.days / 30)
                    if diff_month > 6:
                        make_diff_day = f"오래전"
                    elif diff_month >= 1:
                        make_diff_day = f"{diff_month}달전"
                else:
                    diff_min = trunc(diff_time.seconds / 60)
                    make_diff_day = f"{diff_min}분전"

                    if diff_min >= 60:
                        diff_hour = trunc(diff_time.seconds / 3600)
                        make_diff_day = f"{diff_hour}시간전"

                cs_entitiy.create_diff_day = make_diff_day
        cursor = {
            # "previous_id": cs_entities[-1].id if cs_entities else None,
            "current_page_no": dto.page_no,
            "total_cs_cnt": total_cs_cnt,
        }

        return UseCaseSuccessOutput(value={"data": cs_entities, "cursor": cursor})


class UpdateAdminCSUseCase(AdminBaseUseCase):
    def execute(
        self, dto: UpdateAdminCSDto
    ) -> UseCaseSuccessOutput | UseCaseFailureOutput:
        if not self._admin_repo.is_check_admin_user(user_id=dto.user_id):
            return UseCaseFailureOutput(
                type="not admin permission",
                message=FailureType.UNAUTHORIZED_ERROR,
                code=HTTPStatus.UNAUTHORIZED,
            )

        self._admin_repo.update_cs(inquiry_id=dto.inquiry_id, is_solved=dto.is_solved)
        return UseCaseSuccessOutput()
