import datetime
from math import trunc
from typing import List

import inject
from pytz import timezone

from app.extensions.utils.time_helper import get_server_timestamp
from core.domains.notification.dto.notification_dto import (
    UpdateNotificationReadDto,
    GetNotificationDto,
    GetBadgeDto,
    UpdateNotificationAllReadDto,
)
from core.domains.notification.entity.notification_entity import NotificationEntity
from core.domains.notification.repository.notification_repository import (
    NotificationRepository,
)
from core.use_case_output import UseCaseSuccessOutput, UseCaseFailureOutput


class NotificationBaseUseCase:
    @inject.autoparams()
    def __init__(
        self, notification_repo: NotificationRepository,
    ):
        self._notification_repo = notification_repo


class UpdateNotificationReadUseCase(NotificationBaseUseCase):
    def execute(
        self, dto: UpdateNotificationReadDto
    ) -> UseCaseSuccessOutput | UseCaseFailureOutput:
        self._notification_repo.update_notification_read(
            notification_id=dto.notification_id
        )
        return UseCaseSuccessOutput()


class UpdateNotificationAllReadUseCase(NotificationBaseUseCase):
    def execute(
        self, dto: UpdateNotificationAllReadDto
    ) -> UseCaseSuccessOutput | UseCaseFailureOutput:
        self._notification_repo.update_notification_all_read(user_id=dto.user_id)
        return UseCaseSuccessOutput()


class GetNotificationUseCase(NotificationBaseUseCase):
    def execute(
        self, dto: GetNotificationDto
    ) -> UseCaseSuccessOutput | UseCaseFailureOutput:
        notifications: List[
            NotificationEntity
        ] | None = self._notification_repo.get_notifications(
            user_id=dto.user_id, previous_id=dto.previous_id
        )
        if notifications:
            for notification in notifications:
                kst_time = notification.created_at + datetime.timedelta(hours=9)
                created_at = kst_time.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}시간전"

                notification.create_diff_day = make_diff_day

        cursor = {
            "previous_id": notifications[-1].id if notifications else None,
            "current_id": dto.previous_id,
        }

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


class GetBadgeUseCase(NotificationBaseUseCase):
    def execute(self, dto: GetBadgeDto) -> UseCaseSuccessOutput | UseCaseFailureOutput:
        result: bool = self._notification_repo.get_badge(user_id=dto.user_id)
        return UseCaseSuccessOutput(value=result)
