import re

import pytest
import pytest_mock
from temporalio.testing import ActivityEnvironment

from csirtmu.beta_temporal.commons.actions import RTCommonActions
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


class TestRtCommonActions:
    async def test_close_ticket(
        self,
        worker_config: WorkerConfig,
        test_activity_env: ActivityEnvironment,
        mocker: pytest_mock.MockerFixture,
    ) -> None:
        activities = RTCommonActions(RTClient(worker_config.rt))
        edit_ticket_mock = mocker.patch(
            "csirtmu.beta_temporal.commons.actions.rt_common_actions.RTClient.edit_ticket",
        )
        edit_ticket_mock.return_value = None
        await test_activity_env.run(activities.close_ticket, 1)
        edit_ticket_mock.assert_called_once_with(1, Status="Resolved")

    async def test_set_custom_field_ticket_obj_is_none(
        self,
        worker_config: WorkerConfig,
        test_activity_env: ActivityEnvironment,
        mock_transaction_obj: structs.TransactionStruct,
    ) -> None:
        activities = RTCommonActions(RTClient(worker_config.rt))
        mock_transaction_obj.ticket_obj = None
        with pytest.raises(ValueError, match=re.escape(f"TicketObj in transaction: {mock_transaction_obj} is None.")):
            await test_activity_env.run(activities.set_custom_field, "Category", "Spam", mock_transaction_obj)

    async def test_set_custom_field(
        self,
        worker_config: WorkerConfig,
        test_activity_env: ActivityEnvironment,
        mock_transaction_obj: structs.TransactionStruct,
        mocker: pytest_mock.MockerFixture,
    ) -> None:
        assert mock_transaction_obj.ticket_obj is not None
        activities = RTCommonActions(RTClient(worker_config.rt))
        edit_custom_field_mock = mocker.patch(
            "csirtmu.beta_temporal.commons.actions.rt_common_actions.RTClient.edit_custom_field"
        )
        edit_custom_field_mock.return_value = None
        await test_activity_env.run(activities.set_custom_field, "Category", "Spam", mock_transaction_obj)

        edit_custom_field_mock.assert_called_once_with(mock_transaction_obj.ticket_obj.id, "Category", "Spam")

    async def test_set_ticket_priority_ticket_obj_is_none(
        self,
        worker_config: WorkerConfig,
        mock_transaction_obj: structs.TransactionStruct,
        test_activity_env: ActivityEnvironment,
    ) -> None:
        activities = RTCommonActions(RTClient(worker_config.rt))
        mock_transaction_obj.ticket_obj = None
        with pytest.raises(ValueError, match=re.escape(f"TicketObj in transaction: {mock_transaction_obj} is None.")):
            await test_activity_env.run(activities.set_ticket_priority, 1, mock_transaction_obj)

    async def test_set_ticket_priority(
        self,
        worker_config: WorkerConfig,
        mock_transaction_obj: structs.TransactionStruct,
        test_activity_env: ActivityEnvironment,
        mocker: pytest_mock.MockerFixture,
    ) -> None:
        assert mock_transaction_obj.ticket_obj is not None
        edit_ticket_mock = mocker.patch(
            "csirtmu.beta_temporal.commons.actions.rt_common_actions.RTClient.edit_ticket",
        )
        edit_ticket_mock.return_value = None
        activities = RTCommonActions(RTClient(worker_config.rt))
        mock_transaction_obj.ticket_obj.id = 1
        await test_activity_env.run(activities.set_ticket_priority, 1, mock_transaction_obj)
        edit_ticket_mock.assert_called_once_with(mock_transaction_obj.ticket_obj.id, Priority=1)

    async def test_set_ticket_status_ticket_obj_is_none(
        self,
        worker_config: WorkerConfig,
        mock_transaction_obj: structs.TransactionStruct,
        test_activity_env: ActivityEnvironment,
        mocker: pytest_mock.MockerFixture,
    ) -> None:
        activities = RTCommonActions(RTClient(worker_config.rt))
        mock_transaction_obj.ticket_obj = None
        edit_ticket_mock = mocker.patch(
            "csirtmu.beta_temporal.commons.actions.rt_common_actions.RTClient.edit_ticket",
        )
        edit_ticket_mock.return_value = None
        get_ticket_mock = mocker.patch(
            "csirtmu.beta_temporal.commons.actions.rt_common_actions.RTClient.get_ticket",
        )
        get_ticket_mock.return_value = None
        await test_activity_env.run(activities.set_ticket_status, "Test", mock_transaction_obj, False)
        edit_ticket_mock.assert_not_called()
        get_ticket_mock.assert_not_called()

    async def test_set_ticket_status_verify_status_is_false(
        self,
        worker_config: WorkerConfig,
        mock_transaction_obj: structs.TransactionStruct,
        test_activity_env: ActivityEnvironment,
        mocker: pytest_mock.MockerFixture,
    ) -> None:
        assert mock_transaction_obj.ticket_obj is not None
        activities = RTCommonActions(RTClient(worker_config.rt))
        edit_ticket_mock = mocker.patch(
            "csirtmu.beta_temporal.commons.actions.rt_common_actions.RTClient.edit_ticket",
        )
        edit_ticket_mock.return_value = None
        get_ticket_mock = mocker.patch(
            "csirtmu.beta_temporal.commons.actions.rt_common_actions.RTClient.get_ticket",
        )
        get_ticket_mock.return_value = None
        await test_activity_env.run(activities.set_ticket_status, "Test", mock_transaction_obj, False)
        edit_ticket_mock.assert_called_once_with(mock_transaction_obj.ticket_obj.id, Status="Test")
        get_ticket_mock.assert_not_called()

    async def test_set_ticket_status_verify_status_is_true_status_is_wrong(
        self,
        worker_config: WorkerConfig,
        mock_ticket_obj: structs.TicketObjStruct,
        mock_transaction_obj: structs.TransactionStruct,
        test_activity_env: ActivityEnvironment,
        mocker: pytest_mock.MockerFixture,
    ) -> None:
        assert mock_transaction_obj.ticket_obj is not None
        activities = RTCommonActions(RTClient(worker_config.rt))
        edit_ticket_mock = mocker.patch(
            "csirtmu.beta_temporal.commons.actions.rt_common_actions.RTClient.edit_ticket",
        )
        edit_ticket_mock.return_value = None
        get_ticket_mock = mocker.patch(
            "csirtmu.beta_temporal.commons.actions.rt_common_actions.RTClient.get_ticket",
        )
        mock_transaction_obj.ticket_obj.status = "status"
        mock_ticket_obj.status = "not status"
        get_ticket_mock.return_value = mock_ticket_obj
        await test_activity_env.run(activities.set_ticket_status, "Test", mock_transaction_obj, True)
        edit_ticket_mock.assert_not_called()
        get_ticket_mock.assert_called_once_with(mock_transaction_obj.ticket_obj.id)

    async def test_set_ticket_status_verify_status_is_true_status_is_correct(
        self,
        worker_config: WorkerConfig,
        mock_ticket_obj: structs.TicketObjStruct,
        mock_transaction_obj: structs.TransactionStruct,
        test_activity_env: ActivityEnvironment,
        mocker: pytest_mock.MockerFixture,
    ) -> None:
        assert mock_transaction_obj.ticket_obj is not None
        activities = RTCommonActions(RTClient(worker_config.rt))
        edit_ticket_mock = mocker.patch(
            "csirtmu.beta_temporal.commons.actions.rt_common_actions.RTClient.edit_ticket",
        )
        edit_ticket_mock.return_value = None
        get_ticket_mock = mocker.patch(
            "csirtmu.beta_temporal.commons.actions.rt_common_actions.RTClient.get_ticket",
        )
        mock_transaction_obj.ticket_obj.status = "status"
        mock_ticket_obj.status = "status"
        get_ticket_mock.return_value = mock_ticket_obj
        await test_activity_env.run(activities.set_ticket_status, "Test", mock_transaction_obj, True)
        edit_ticket_mock.assert_called_once_with(mock_transaction_obj.ticket_obj.id, Status="Test")
        get_ticket_mock.assert_called_once_with(mock_transaction_obj.ticket_obj.id)

    async def test_set_ip_related_custom_fields_ticket_obj_is_none(
        self,
        worker_config: WorkerConfig,
        mock_transaction_obj: structs.TransactionStruct,
        test_activity_env: ActivityEnvironment,
        mocker: pytest_mock.MockerFixture,
    ) -> None:
        activities = RTCommonActions(RTClient(worker_config.rt))
        edit_ticket_mock = mocker.patch(
            "csirtmu.beta_temporal.commons.actions.rt_common_actions.RTClient.edit_ticket",
        )
        mock_transaction_obj.ticket_obj = None
        await test_activity_env.run(activities.set_ip_related_custom_fields, mock_transaction_obj, {})
        edit_ticket_mock.assert_not_called()

    async def test_set_ip_related_custom_fields_create(
        self,
        worker_config: WorkerConfig,
        mock_ticket_obj: structs.TicketObjStruct,
        mock_transaction_obj: structs.TransactionStruct,
        test_activity_env: ActivityEnvironment,
        mocker: pytest_mock.MockerFixture,
    ) -> None:
        activities = RTCommonActions(RTClient(worker_config.rt))
        edit_ticket_mock = mocker.patch(
            "csirtmu.beta_temporal.commons.actions.rt_common_actions.RTClient.edit_ticket",
        )
        mock_ticket_obj.id = 1234567
        mock_transaction_obj.ticket_obj = mock_ticket_obj
        mock_transaction_obj.type = structs.TransactionTypeEnum.CREATE
        await test_activity_env.run(activities.set_ip_related_custom_fields, mock_transaction_obj, {"Test": ["Test"]})
        edit_ticket_mock.assert_called_once_with(1234567, CustomFields={"Test": ["Test"]})

    async def test_set_ip_related_custom_fields_correspond_new_cf(
        self,
        worker_config: WorkerConfig,
        mock_ticket_obj: structs.TicketObjStruct,
        mock_transaction_obj: structs.TransactionStruct,
        test_activity_env: ActivityEnvironment,
        mocker: pytest_mock.MockerFixture,
    ) -> None:
        activities = RTCommonActions(RTClient(worker_config.rt))
        edit_ticket_mock = mocker.patch(
            "csirtmu.beta_temporal.commons.actions.rt_common_actions.RTClient.edit_ticket",
        )
        mock_ticket_obj.id = 1234567
        mock_transaction_obj.ticket_obj = mock_ticket_obj
        mock_transaction_obj.type = structs.TransactionTypeEnum.CORRESPOND
        await test_activity_env.run(activities.set_ip_related_custom_fields, mock_transaction_obj, {"Test": ["Test"]})
        edit_ticket_mock.assert_called_once_with(1234567, CustomFields={"Test": ["Test"]})

    async def test_set_ip_related_custom_fields_correspond_duplicate_cf_diff_value(
        self,
        worker_config: WorkerConfig,
        mock_ticket_obj: structs.TicketObjStruct,
        mock_transaction_obj: structs.TransactionStruct,
        test_activity_env: ActivityEnvironment,
        mocker: pytest_mock.MockerFixture,
    ) -> None:
        activities = RTCommonActions(RTClient(worker_config.rt))
        edit_ticket_mock = mocker.patch(
            "csirtmu.beta_temporal.commons.actions.rt_common_actions.RTClient.edit_ticket",
        )
        mock_ticket_obj.id = 1234567
        mock_ticket_obj.custom_fields = [structs.CustomFieldStruct("", "", "", "Test", ["idk"])]
        mock_transaction_obj.ticket_obj = mock_ticket_obj
        mock_transaction_obj.type = structs.TransactionTypeEnum.CORRESPOND
        await test_activity_env.run(activities.set_ip_related_custom_fields, mock_transaction_obj, {"Test": ["Test"]})
        edit_ticket_mock.assert_called_once_with(1234567, CustomFields={"Test": ["Test"]})

    async def test_set_ip_related_custom_fields_correspond_duplicate_cf_duplicate_value(
        self,
        worker_config: WorkerConfig,
        mock_ticket_obj: structs.TicketObjStruct,
        mock_transaction_obj: structs.TransactionStruct,
        test_activity_env: ActivityEnvironment,
        mocker: pytest_mock.MockerFixture,
    ) -> None:
        activities = RTCommonActions(RTClient(worker_config.rt))
        edit_ticket_mock = mocker.patch(
            "csirtmu.beta_temporal.commons.actions.rt_common_actions.RTClient.edit_ticket",
        )
        mock_ticket_obj.id = 1234567
        mock_ticket_obj.custom_fields = [structs.CustomFieldStruct("", "", "", "Test", ["Test"])]
        mock_transaction_obj.ticket_obj = mock_ticket_obj
        mock_transaction_obj.type = structs.TransactionTypeEnum.CORRESPOND
        await test_activity_env.run(activities.set_ip_related_custom_fields, mock_transaction_obj, {"Test": ["Test"]})
        edit_ticket_mock.assert_not_called()
