import os
import uuid
from unittest.mock import patch

from faker import Faker

from app.extensions.utils.enum.aws_enum import S3PathEnum, CloudFrontEnum
from app.persistence.model import PostModel
from core.domains.community.dto.community_dto import (
    CreatePostAttachmentDto,
    DeletePostDto,
    UpdatePostLikeStatusDto,
    CreateCommentDto,
    UpdateCommentDto,
    DeleteCommentDto,
    UpdateCommentLikeStatusDto,
)
from core.domains.community.entity.community_entity import PostEntity
from core.domains.community.use_case.v1.community_use_case import (
    CreatePostUseCase,
    UpdatePostUseCase,
    DeletePostUseCase,
    UpdatePostLikeStatusUseCase,
    CreateCommentUseCase,
    UpdateCommentUseCase,
    DeleteCommentUseCase,
    UpdateCommentLikeStatusUseCase,
)
from core.use_case_output import UseCaseSuccessOutput, UseCaseFailureOutput

faker = Faker()


def test_us_create_post_when_with_files_then_success(
    session, create_post_dto, create_post_attachment_dtos
):
    with patch(
        "core.domains.community.use_case.v1.community_use_case.CreatePostUseCase._get_file_split_object",
    ) as _get_file_split_object:
        _get_file_split_object.return_value = create_post_attachment_dtos

        with patch(
            "core.domains.community.use_case.v1.community_use_case.CreatePostUseCase._upload_post_attachments",
        ) as _upload_post_attachments:
            create_post_attachment_dto = create_post_attachment_dtos[-1]
            create_post_attachment_dto.is_upload = None

            _upload_post_attachments.return_value = create_post_dto

            result = CreatePostUseCase().execute(dto=create_post_dto)

        query_result: PostEntity = session.query(PostModel).filter_by(id=1).first()

    assert isinstance(result, UseCaseSuccessOutput)
    assert query_result.body == create_post_dto.body
    assert len(query_result.post_attachments) == len(create_post_dto.files) - 1


def test_us_create_post_when_without_files_then_success(session, create_post_dto):
    create_post_dto.files = []
    result = CreatePostUseCase().execute(dto=create_post_dto)

    assert isinstance(result, UseCaseSuccessOutput)


@patch(
    "core.domains.community.repository.community_repository.CommunityRepository.get_post_by_id"
)
def test_us_update_post_when_with_files_then_success(
    get_post_by_id, session, create_post, update_post_dto
):
    get_post_by_id.return_value = create_post.to_entity()
    update_post_dto.user_id = create_post.user_id

    with patch(
        "core.domains.community.use_case.v1.community_use_case.UpdatePostUseCase._get_file_split_object",
    ) as _get_file_split_object:
        create_post_attachment_dtos = list()
        for file in update_post_dto.files:
            file_uuid = str(uuid.uuid4())
            f, extension = os.path.splitext(file.filename)

            object_name = S3PathEnum.PROFILE_IMGS.value + file_uuid + extension
            path = f"{CloudFrontEnum.PLANTRA_CLOUD_FRONT_DOMAIN.value}/{object_name}"

            create_post_attachment_dto = CreatePostAttachmentDto(
                post_id=update_post_dto.post_id,
                uuid=file_uuid,
                file_name=f,
                path=path,
                extension=extension,
                object_name=object_name,
                origin_file=file,
                is_upload=True,  # mock 처리 할 것이기 때문에 True로 처리
            )
            create_post_attachment_dtos.append(create_post_attachment_dto)

        _get_file_split_object.return_value = create_post_attachment_dtos

        with patch(
            "core.domains.community.use_case.v1.community_use_case.UpdatePostUseCase._upload_post_attachments",
        ) as _upload_post_attachments:
            _upload_post_attachments.return_value = update_post_dto
            result = UpdatePostUseCase().execute(dto=update_post_dto)

    assert isinstance(result, UseCaseSuccessOutput)


@patch(
    "core.domains.community.repository.community_repository.CommunityRepository.get_post_by_id"
)
def test_us_delete_post_then_success(get_post_by_id, session, create_post):
    get_post_by_id.return_value = create_post.to_entity()
    delete_post_dto = DeletePostDto(post_id=create_post.id, user_id=create_post.user_id)

    result = DeletePostUseCase().execute(dto=delete_post_dto)

    assert isinstance(result, UseCaseSuccessOutput)


@patch(
    "core.domains.user.repository.user_repository.UserRepository.get_user_nickname",
    return_value="Tester",
)
def test_us_update_post_when_insert_like_status_then_success(session, create_post):
    update_post_like_status_dto = UpdatePostLikeStatusDto(
        post_id=create_post.id, user_id=create_post.user_id + 1, is_liked=True
    )
    result = UpdatePostLikeStatusUseCase().execute(dto=update_post_like_status_dto)

    assert isinstance(result, UseCaseSuccessOutput)


@patch(
    "core.domains.user.repository.user_repository.UserRepository.get_user_nickname",
    return_value="Tester",
)
def test_us_update_post_when_update_like_status_then_success(session, create_post):
    update_post_like_status_dto = UpdatePostLikeStatusDto(
        post_id=create_post.id, user_id=create_post.user_id, is_liked=True
    )
    result = UpdatePostLikeStatusUseCase().execute(dto=update_post_like_status_dto)

    assert isinstance(result, UseCaseSuccessOutput)


def test_us_create_comment_when_empty_body_then_success(session, create_post):
    create_comment_dto = CreateCommentDto(
        post_id=create_post.id, user_id=create_post.user_id + 1, body="",
    )
    result = CreateCommentUseCase().execute(dto=create_comment_dto)

    assert isinstance(result, UseCaseFailureOutput)


def test_us_update_comment_then_success(session, create_post):
    update_comment_dto = UpdateCommentDto(
        comment_id=create_post.comments[0].id,
        user_id=create_post.comments[0].user_id,
        body=faker.sentence(),
    )
    result = UpdateCommentUseCase().execute(dto=update_comment_dto)

    assert isinstance(result, UseCaseSuccessOutput)


def test_us_delete_comment_then_success(session, create_post):
    delete_comment_dto = DeleteCommentDto(
        user_id=create_post.comments[0].user_id, comment_id=create_post.comments[0].id,
    )
    result = DeleteCommentUseCase().execute(dto=delete_comment_dto)

    assert isinstance(result, UseCaseSuccessOutput)


def test_us_update_comment_when_insert_like_status_then_success(session, create_post):
    update_comment_like_status_dto = UpdateCommentLikeStatusDto(
        comment_id=create_post.comments[0].id,
        user_id=create_post.user_id + 1,
        is_liked=True,
    )
    result = UpdateCommentLikeStatusUseCase().execute(
        dto=update_comment_like_status_dto
    )

    assert isinstance(result, UseCaseSuccessOutput)
