import base64
import hashlib

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.workflows.hash_discovered_attachments import HashDiscoveredAttachmentsActivities


class TestHashAttachments:
    async def test_hash_attachments_ticket_obj_is_none(
        self,
        worker_config: WorkerConfig,
        mock_transaction_obj: structs.TransactionStruct,
        test_activity_env: ActivityEnvironment,
    ) -> None:
        activities = HashDiscoveredAttachmentsActivities(RTClient(worker_config.rt))
        mock_transaction_obj.ticket_obj = None
        assert (await test_activity_env.run(activities.hash_attachments, mock_transaction_obj)) is None

    async def test_hash_attachments_ticket_data_is_none(
        self,
        worker_config: WorkerConfig,
        mock_transaction_obj: structs.TransactionStruct,
        test_activity_env: ActivityEnvironment,
        mocker: pytest_mock.MockerFixture,
    ) -> None:
        activities = HashDiscoveredAttachmentsActivities(RTClient(worker_config.rt))
        get_ticket_data_mock = mocker.patch(
            "csirtmu.beta_temporal.workflows.hash_discovered_attachments.RTClient.get_ticket_data"
        )
        get_ticket_data_mock.return_value = None
        assert (await test_activity_env.run(activities.hash_attachments, mock_transaction_obj)) is None
        get_ticket_data_mock.assert_called_once_with(mock_transaction_obj)

    async def test_hash_attachments_no_attachments(
        self,
        worker_config: WorkerConfig,
        mock_transaction_obj: structs.TransactionStruct,
        test_activity_env: ActivityEnvironment,
        mock_ticket_data: structs.TicketData,
        mocker: pytest_mock.MockerFixture,
    ) -> None:
        # Prepare
        activities = HashDiscoveredAttachmentsActivities(RTClient(worker_config.rt))
        get_ticket_data_mock = mocker.patch(
            "csirtmu.beta_temporal.workflows.hash_discovered_attachments.RTClient.get_ticket_data"
        )
        mock_ticket_data.attachments = []
        get_ticket_data_mock.return_value = mock_ticket_data
        edit_ticket_mock = mocker.patch(
            "csirtmu.beta_temporal.workflows.hash_discovered_attachments.RTClient.edit_ticket"
        )
        edit_ticket_mock.return_value = None

        # Run
        await test_activity_env.run(activities.hash_attachments, mock_transaction_obj)

        # Check
        assert mock_transaction_obj.ticket_obj is not None
        get_ticket_data_mock.assert_called_once_with(mock_transaction_obj)
        edit_ticket_mock.assert_called_once_with(
            mock_transaction_obj.ticket_obj.id, CustomFields={"Attachment hashes": []}
        )

    async def test_hash_attachments_single_attachment_no_existing(
        self,
        worker_config: WorkerConfig,
        mock_transaction_obj: structs.TransactionStruct,
        test_activity_env: ActivityEnvironment,
        mock_ticket_data: structs.TicketData,
        mocker: pytest_mock.MockerFixture,
    ) -> None:
        # Prepare
        activities = HashDiscoveredAttachmentsActivities(RTClient(worker_config.rt))
        get_ticket_data_mock = mocker.patch(
            "csirtmu.beta_temporal.workflows.hash_discovered_attachments.RTClient.get_ticket_data"
        )
        mock_ticket_data.attachments[0].filename = "test_file.txt"
        mock_ticket_data.attachments[0].content_type = "txt/html"
        mock_ticket_data.attachments[0].content = base64.b64encode(b"test_content_test_content").decode("utf-8")
        get_ticket_data_mock.return_value = mock_ticket_data
        edit_ticket_mock = mocker.patch(
            "csirtmu.beta_temporal.workflows.hash_discovered_attachments.RTClient.edit_ticket"
        )
        edit_ticket_mock.return_value = None
        hash = (
            hashlib.sha256(base64.b64decode(mock_ticket_data.attachments[0].content)).hexdigest()
            + "\t"
            + mock_ticket_data.attachments[0].filename
        )

        # Run
        await test_activity_env.run(activities.hash_attachments, mock_transaction_obj)

        # Check
        assert mock_transaction_obj.ticket_obj is not None
        get_ticket_data_mock.assert_called_once_with(mock_transaction_obj)
        edit_ticket_mock.assert_called_once_with(
            mock_transaction_obj.ticket_obj.id, CustomFields={"Attachment hashes": [hash]}
        )

    async def test_hash_attachments_single_attachment_existing_hashes(
        self,
        worker_config: WorkerConfig,
        mock_transaction_obj: structs.TransactionStruct,
        test_activity_env: ActivityEnvironment,
        mock_ticket_data: structs.TicketData,
        mocker: pytest_mock.MockerFixture,
    ) -> None:
        assert mock_transaction_obj.ticket_obj is not None
        # Prepare
        activities = HashDiscoveredAttachmentsActivities(RTClient(worker_config.rt))
        get_ticket_data_mock = mocker.patch(
            "csirtmu.beta_temporal.workflows.hash_discovered_attachments.RTClient.get_ticket_data"
        )
        mock_ticket_data.attachments[0].filename = "test_file.txt"
        mock_ticket_data.attachments[0].content_type = "txt/html"
        mock_ticket_data.attachments[0].content = base64.b64encode(b"test_content_test_content").decode("utf-8")
        mock_transaction_obj.ticket_obj.custom_fields = [
            structs.CustomFieldStruct(id="", url="", type="", name="Attachment hashes", _values=["Test hash"]),
        ]
        get_ticket_data_mock.return_value = mock_ticket_data
        edit_ticket_mock = mocker.patch(
            "csirtmu.beta_temporal.workflows.hash_discovered_attachments.RTClient.edit_ticket"
        )
        edit_ticket_mock.return_value = None
        hash = (
            hashlib.sha256(base64.b64decode(mock_ticket_data.attachments[0].content)).hexdigest()
            + "\t"
            + mock_ticket_data.attachments[0].filename
        )

        # Run
        await test_activity_env.run(activities.hash_attachments, mock_transaction_obj)

        # Check
        get_ticket_data_mock.assert_called_once_with(mock_transaction_obj)
        edit_ticket_mock.assert_called_once_with(
            mock_transaction_obj.ticket_obj.id, CustomFields={"Attachment hashes": ["Test hash", hash]}
        )

    async def test_hash_attachments_duplicate_attachment_existing_hashes(
        self,
        worker_config: WorkerConfig,
        mock_transaction_obj: structs.TransactionStruct,
        test_activity_env: ActivityEnvironment,
        mock_ticket_data: structs.TicketData,
        mocker: pytest_mock.MockerFixture,
    ) -> None:
        assert mock_transaction_obj.ticket_obj is not None
        # Prepare
        activities = HashDiscoveredAttachmentsActivities(RTClient(worker_config.rt))
        get_ticket_data_mock = mocker.patch(
            "csirtmu.beta_temporal.workflows.hash_discovered_attachments.RTClient.get_ticket_data"
        )
        mock_ticket_data.attachments[0].filename = "test_file.txt"
        mock_ticket_data.attachments[0].content_type = "txt/html"
        mock_ticket_data.attachments[0].content = base64.b64encode(b"test_content_test_content").decode("utf-8")
        mock_ticket_data.attachments.append(mock_ticket_data.attachments[0])
        mock_transaction_obj.ticket_obj.custom_fields = [
            structs.CustomFieldStruct(id="", url="", type="", name="Attachment hashes", _values=["Test hash"]),
        ]
        get_ticket_data_mock.return_value = mock_ticket_data
        edit_ticket_mock = mocker.patch(
            "csirtmu.beta_temporal.workflows.hash_discovered_attachments.RTClient.edit_ticket"
        )
        edit_ticket_mock.return_value = None
        hash = (
            hashlib.sha256(base64.b64decode(mock_ticket_data.attachments[0].content)).hexdigest()
            + "\t"
            + mock_ticket_data.attachments[0].filename
        )

        # Run
        await test_activity_env.run(activities.hash_attachments, mock_transaction_obj)

        # Check
        get_ticket_data_mock.assert_called_once_with(mock_transaction_obj)
        edit_ticket_mock.assert_called_once_with(
            mock_transaction_obj.ticket_obj.id, CustomFields={"Attachment hashes": ["Test hash", hash]}
        )
