import pytest
import pytest_mock
from temporalio.testing import ActivityEnvironment

from csirtmu.beta_temporal.config import Config as WorkerConfig
from csirtmu.beta_temporal.external_services.rt import structs
from csirtmu.beta_temporal.external_services.rt.client import RTClient
from csirtmu.beta_temporal.external_services.rt.utils import get_return_mail_map
from csirtmu.beta_temporal.workflows.set_status_rejected_on_returned_mail import (
    SetStatusRejectedOnReturnedMailActivities,
)


class TestIsReturnedMail:
    async def test_is_returned_mail_ticket_obj_is_none(
        self,
        worker_config: WorkerConfig,
        mock_transaction_obj: structs.TransactionStruct,
        test_activity_env: ActivityEnvironment,
        mocker: pytest_mock.MockerFixture,
    ) -> None:
        activities = SetStatusRejectedOnReturnedMailActivities(RTClient(worker_config.rt))
        mock_transaction_obj.ticket_obj = None
        get_ticket_data_mock = mocker.patch(
            "csirtmu.beta_temporal.workflows.set_status_rejected_on_returned_mail.RTClient.get_ticket_data",
        )
        assert not await test_activity_env.run(activities.is_returned_mail, mock_transaction_obj)
        get_ticket_data_mock.assert_not_called()

    async def test_is_returned_mail_ticket_data_is_none(
        self,
        worker_config: WorkerConfig,
        mock_transaction_obj: structs.TransactionStruct,
        test_activity_env: ActivityEnvironment,
        mocker: pytest_mock.MockerFixture,
    ) -> None:
        activities = SetStatusRejectedOnReturnedMailActivities(RTClient(worker_config.rt))
        mock_transaction_obj.type = structs.TransactionTypeEnum.CREATE
        get_ticket_data_mock = mocker.patch(
            "csirtmu.beta_temporal.workflows.set_status_rejected_on_returned_mail.RTClient.get_ticket_data",
        )
        get_ticket_data_mock.return_value = None
        assert not await test_activity_env.run(activities.is_returned_mail, mock_transaction_obj)
        get_ticket_data_mock.assert_called_once_with(mock_transaction_obj)

    async def test_is_returned_mail_no_sender_matches(
        self,
        worker_config: WorkerConfig,
        mock_ticket_data: structs.TicketData,
        mock_transaction_obj: structs.TransactionStruct,
        test_activity_env: ActivityEnvironment,
        mocker: pytest_mock.MockerFixture,
    ) -> None:
        activities = SetStatusRejectedOnReturnedMailActivities(RTClient(worker_config.rt))
        mock_transaction_obj.type = structs.TransactionTypeEnum.CREATE
        get_ticket_data_mock = mocker.patch(
            "csirtmu.beta_temporal.workflows.set_status_rejected_on_returned_mail.RTClient.get_ticket_data",
        )
        get_ticket_data_mock.return_value = mock_ticket_data
        assert not await test_activity_env.run(activities.is_returned_mail, mock_transaction_obj)
        get_ticket_data_mock.assert_called_once_with(mock_transaction_obj)

    @pytest.mark.parametrize("sender", [x.get("Sender") for x in get_return_mail_map()])
    async def test_is_returned_mail_only_senders_match(
        self,
        sender: str,
        worker_config: WorkerConfig,
        mock_ticket_data: structs.TicketData,
        mock_transaction_obj: structs.TransactionStruct,
        test_activity_env: ActivityEnvironment,
        mocker: pytest_mock.MockerFixture,
    ) -> None:
        activities = SetStatusRejectedOnReturnedMailActivities(RTClient(worker_config.rt))
        mock_transaction_obj.type = structs.TransactionTypeEnum.CREATE
        get_ticket_data_mock = mocker.patch(
            "csirtmu.beta_temporal.workflows.set_status_rejected_on_returned_mail.RTClient.get_ticket_data",
        )
        mock_ticket_data.headers.add_header("From", sender)
        get_ticket_data_mock.return_value = mock_ticket_data
        assert not await test_activity_env.run(activities.is_returned_mail, mock_transaction_obj)
        get_ticket_data_mock.assert_called_once_with(mock_transaction_obj)

    @pytest.mark.parametrize(
        ("sender", "subject", "content"),
        [(x.get("Sender"), x.get("Subject"), x.get("Content")) for x in get_return_mail_map()],
    )
    async def test_is_returned_mail_only_subjects_match(
        self,
        sender: str | None,
        subject: str | None,
        content: str | None,
        worker_config: WorkerConfig,
        mock_ticket_data: structs.TicketData,
        mock_transaction_obj: structs.TransactionStruct,
        test_activity_env: ActivityEnvironment,
        mocker: pytest_mock.MockerFixture,
    ) -> None:
        assert mock_transaction_obj.ticket_obj is not None
        activities = SetStatusRejectedOnReturnedMailActivities(RTClient(worker_config.rt))
        mock_transaction_obj.type = structs.TransactionTypeEnum.CREATE
        get_ticket_data_mock = mocker.patch(
            "csirtmu.beta_temporal.workflows.set_status_rejected_on_returned_mail.RTClient.get_ticket_data",
        )
        mock_transaction_obj.ticket_obj.subject = subject or ""
        get_ticket_data_mock.return_value = mock_ticket_data
        if content is None and sender is None:
            assert await test_activity_env.run(activities.is_returned_mail, mock_transaction_obj)
        else:
            assert not await test_activity_env.run(activities.is_returned_mail, mock_transaction_obj)
        get_ticket_data_mock.assert_called_once_with(mock_transaction_obj)

    @pytest.mark.parametrize(
        ("sender", "subject", "content"),
        [(x.get("Sender"), x.get("Subject"), x.get("Content")) for x in get_return_mail_map()],
    )
    async def test_is_returned_mail_only_contents_match(
        self,
        sender: str | None,
        subject: str | None,
        content: str | None,
        worker_config: WorkerConfig,
        mock_ticket_data: structs.TicketData,
        mock_transaction_obj: structs.TransactionStruct,
        test_activity_env: ActivityEnvironment,
        mocker: pytest_mock.MockerFixture,
    ) -> None:
        assert mock_transaction_obj.ticket_obj is not None
        activities = SetStatusRejectedOnReturnedMailActivities(RTClient(worker_config.rt))
        mock_transaction_obj.type = structs.TransactionTypeEnum.CREATE
        get_ticket_data_mock = mocker.patch(
            "csirtmu.beta_temporal.workflows.set_status_rejected_on_returned_mail.RTClient.get_ticket_data",
        )
        mock_ticket_data.body = content or ""
        get_ticket_data_mock.return_value = mock_ticket_data
        if subject is None and sender is None:
            assert await test_activity_env.run(activities.is_returned_mail, mock_transaction_obj)
        else:
            assert not await test_activity_env.run(activities.is_returned_mail, mock_transaction_obj)
        get_ticket_data_mock.assert_called_once_with(mock_transaction_obj)

    @pytest.mark.parametrize(
        ("sender", "subject", "content"),
        [(x.get("Sender"), x.get("Subject"), x.get("Content")) for x in get_return_mail_map()],
    )
    async def test_is_returned_mail_test_matches(
        self,
        sender: str | None,
        subject: str | None,
        content: str | None,
        worker_config: WorkerConfig,
        mock_ticket_data: structs.TicketData,
        mock_transaction_obj: structs.TransactionStruct,
        test_activity_env: ActivityEnvironment,
        mocker: pytest_mock.MockerFixture,
    ) -> None:
        assert mock_transaction_obj.ticket_obj is not None
        activities = SetStatusRejectedOnReturnedMailActivities(RTClient(worker_config.rt))
        mock_transaction_obj.type = structs.TransactionTypeEnum.CREATE
        get_ticket_data_mock = mocker.patch(
            "csirtmu.beta_temporal.workflows.set_status_rejected_on_returned_mail.RTClient.get_ticket_data",
        )
        mock_ticket_data.headers.add_header("From", sender or "")
        mock_transaction_obj.ticket_obj.subject = subject or ""
        get_ticket_data_mock.return_value = mock_ticket_data
        if content is None:
            assert await test_activity_env.run(activities.is_returned_mail, mock_transaction_obj)
        else:
            assert not await test_activity_env.run(activities.is_returned_mail, mock_transaction_obj)
        get_ticket_data_mock.assert_called_once_with(mock_transaction_obj)
