"""Tests for the sop_class module."""

import pytest

from pynetdicom import __version__
from pydicom._uid_dict import UID_dictionary

from pynetdicom.sop_class import (
    uid_to_sop_class,
    uid_to_service_class,
    SOPClass,
    _SERVICE_CLASSES,
    _APPLICATION_EVENT_CLASSES,
    ProceduralEventLogging,
    _BASIC_WORKLIST_CLASSES,
    ModalityWorklistInformationFind,
    _COLOR_PALETTE_CLASSES,
    ColorPaletteInformationModelMove,
    _DEFINED_PROCEDURE_CLASSES,
    DefinedProcedureProtocolInformationModelFind,
    _DISPLAY_SYSTEM_CLASSES,
    DisplaySystem,
    _HANGING_PROTOCOL_CLASSES,
    HangingProtocolInformationModelGet,
    _IMPLANT_TEMPLATE_CLASSES,
    ImplantTemplateGroupInformationModelFind,
    _INSTANCE_AVAILABILITY_CLASSES,
    InstanceAvailabilityNotification,
    _MEDIA_CREATION_CLASSES,
    MediaCreationManagement,
    _MEDIA_STORAGE_CLASSES,
    MediaStorageDirectoryStorage,
    _NON_PATIENT_OBJECT_CLASSES,
    HangingProtocolStorage,
    _PRINT_MANAGEMENT_CLASSES,
    PrintJob,
    _PROCEDURE_STEP_CLASSES,
    ModalityPerformedProcedureStep,
    _PROTOCOL_APPROVAL_CLASSES,
    ProtocolApprovalInformationModelFind,
    ProtocolApprovalInformationModelMove,
    ProtocolApprovalInformationModelGet,
    _QR_CLASSES,
    StudyRootQueryRetrieveInformationModelFind,
    _RELEVANT_PATIENT_QUERY_CLASSES,
    GeneralRelevantPatientInformationQuery,
    _RT_MACHINE_VERIFICATION_CLASSES,
    RTConventionalMachineVerification,
    _STORAGE_CLASSES,
    CTImageStorage,
    _STORAGE_COMMITMENT_CLASSES,
    StorageCommitmentPushModel,
    _SUBSTANCE_ADMINISTRATION_CLASSES,
    ProductCharacteristicsQuery,
    _UNIFIED_PROCEDURE_STEP_CLASSES,
    UnifiedProcedureStepPull,
    _VERIFICATION_CLASSES,
    Verification,
    DisplaySystemInstance,
    PrinterConfigurationRetrievalInstance,
    PrinterInstance,
    ProceduralEventLoggingInstance,
    StorageCommitmentPushModelInstance,
    SubstanceAdministrationLoggingInstance,
    UPSFilteredGlobalSubscriptionInstance,
    UPSGlobalSubscriptionInstance,
)
from pynetdicom.service_class import (
    ServiceClass,
    BasicWorklistManagementServiceClass,
    ColorPaletteQueryRetrieveServiceClass,
    DefinedProcedureProtocolQueryRetrieveServiceClass,
    HangingProtocolQueryRetrieveServiceClass,
    ImplantTemplateQueryRetrieveServiceClass,
    NonPatientObjectStorageServiceClass,
    ProtocolApprovalQueryRetrieveServiceClass,
    QueryRetrieveServiceClass,
    RelevantPatientInformationQueryServiceClass,
    StorageServiceClass,
    SubstanceAdministrationQueryServiceClass,
    VerificationServiceClass,
)
from pynetdicom.service_class_n import (
    ApplicationEventLoggingServiceClass,
    DisplaySystemManagementServiceClass,
    InstanceAvailabilityNotificationServiceClass,
    MediaCreationManagementServiceClass,
    PrintManagementServiceClass,
    ProcedureStepServiceClass,
    RTMachineVerificationServiceClass,
    StorageCommitmentServiceClass,
    UnifiedProcedureStepServiceClass,
)


PYDICOM_VERSION = __version__.split(".")[:2]


def test_all_sop_classes():
    """Test that all the SOP Class UIDs are correct."""
    for uid in _APPLICATION_EVENT_CLASSES.values():
        assert uid in UID_dictionary
    for uid in _BASIC_WORKLIST_CLASSES.values():
        assert uid in UID_dictionary
    for uid in _COLOR_PALETTE_CLASSES.values():
        assert uid in UID_dictionary
    for uid in _DEFINED_PROCEDURE_CLASSES.values():
        assert uid in UID_dictionary
    for uid in _DISPLAY_SYSTEM_CLASSES.values():
        assert uid in UID_dictionary
    for uid in _HANGING_PROTOCOL_CLASSES.values():
        assert uid in UID_dictionary
    for uid in _IMPLANT_TEMPLATE_CLASSES.values():
        assert uid in UID_dictionary
    for uid in _INSTANCE_AVAILABILITY_CLASSES.values():
        assert uid in UID_dictionary
    for uid in _MEDIA_CREATION_CLASSES.values():
        assert uid in UID_dictionary
    for uid in _MEDIA_STORAGE_CLASSES.values():
        assert uid in UID_dictionary
    for uid in _NON_PATIENT_OBJECT_CLASSES.values():
        assert uid in UID_dictionary
    for uid in _PRINT_MANAGEMENT_CLASSES.values():
        assert uid in UID_dictionary
    for uid in _PROCEDURE_STEP_CLASSES.values():
        assert uid in UID_dictionary
    for uid in _PROTOCOL_APPROVAL_CLASSES.values():
        assert uid in UID_dictionary
    for uid in _QR_CLASSES.values():
        assert uid in UID_dictionary
    for uid in _RELEVANT_PATIENT_QUERY_CLASSES.values():
        assert uid in UID_dictionary
    for uid in _RT_MACHINE_VERIFICATION_CLASSES.values():
        assert uid in UID_dictionary
    if PYDICOM_VERSION >= ["2", "2"]:
        for uid in _STORAGE_CLASSES.values():
            assert uid in UID_dictionary
    for uid in _STORAGE_COMMITMENT_CLASSES.values():
        assert uid in UID_dictionary
    for uid in _SUBSTANCE_ADMINISTRATION_CLASSES.values():
        assert uid in UID_dictionary
    for uid in _UNIFIED_PROCEDURE_STEP_CLASSES.values():
        assert uid in UID_dictionary
    for uid in _VERIFICATION_CLASSES.values():
        assert uid in UID_dictionary


def test_all_service_classes():
    """Test that all the Service Class UIDs are correct."""
    for uid in _SERVICE_CLASSES:
        assert uid in UID_dictionary


def test_all_sop_instances():
    """Test the well-known SOP Instances are correct."""
    assert DisplaySystemInstance in UID_dictionary
    assert PrinterConfigurationRetrievalInstance in UID_dictionary
    assert PrinterInstance in UID_dictionary
    assert ProceduralEventLoggingInstance in UID_dictionary
    assert StorageCommitmentPushModelInstance in UID_dictionary
    assert SubstanceAdministrationLoggingInstance in UID_dictionary
    assert UPSFilteredGlobalSubscriptionInstance in UID_dictionary
    assert UPSGlobalSubscriptionInstance in UID_dictionary


class TestUIDtoSOPlass:
    """Tests for uid_to_sop_class"""

    def test_missing_sop(self):
        """Test SOP Class if UID not found."""
        sop_class = uid_to_sop_class("1.2.3.4")
        assert sop_class == "1.2.3.4"
        assert sop_class.service_class == ServiceClass

    def test_verification_uid(self):
        """Test normal function"""
        assert uid_to_sop_class("1.2.840.10008.1.1") == Verification

    def test_existing(self):
        """Test that the existing class is returned."""
        original = Verification
        sop_class = uid_to_sop_class("1.2.840.10008.1.1")
        assert id(sop_class) == id(original)


class TestUIDToServiceClass:
    """Tests for sop_class.uid_to_service_class."""

    def test_service_class_uid(self):
        uid = "1.2.840.10008.4.2"
        assert uid_to_service_class(uid) == StorageServiceClass

    def test_app_logging_uids(self):
        """Test that the Application Event SOP Class UIDs work correctly."""
        for uid in _APPLICATION_EVENT_CLASSES.values():
            assert uid_to_service_class(uid) == ApplicationEventLoggingServiceClass

    def test_basic_worklist_uids(self):
        """Test that the Basic Worklist SOP Class UIDs work correctly."""
        for uid in _BASIC_WORKLIST_CLASSES.values():
            assert uid_to_service_class(uid) == BasicWorklistManagementServiceClass

    def test_color_palette_uids(self):
        """Test that the Color Paletter SOP Class UIDs work correctly."""
        for uid in _COLOR_PALETTE_CLASSES.values():
            assert uid_to_service_class(uid) == ColorPaletteQueryRetrieveServiceClass

    def test_defined_procedure_uids(self):
        """Test that the Defined Procedure SOP Class UIDs work correctly."""
        for uid in _DEFINED_PROCEDURE_CLASSES.values():
            assert (
                uid_to_service_class(uid)
                == DefinedProcedureProtocolQueryRetrieveServiceClass
            )

    def test_display_system_uids(self):
        """Test that Display System SOP Class UIDs work correctly."""
        for uid in _DISPLAY_SYSTEM_CLASSES.values():
            assert uid_to_service_class(uid) == DisplaySystemManagementServiceClass

    def test_hanging_protocol_uids(self):
        """Test that the Hanging Protocol SOP Class UIDs work correctly."""
        for uid in _HANGING_PROTOCOL_CLASSES.values():
            assert uid_to_service_class(uid) == HangingProtocolQueryRetrieveServiceClass

    def test_implant_template_uids(self):
        """Test that the Implant Template SOP Class UIDs work correctly."""
        for uid in _IMPLANT_TEMPLATE_CLASSES.values():
            assert uid_to_service_class(uid) == ImplantTemplateQueryRetrieveServiceClass

    def test_instance_uids(self):
        """Test that the Instance Availability SOP Class UIDs work correctly."""
        for uid in _INSTANCE_AVAILABILITY_CLASSES.values():
            assert (
                uid_to_service_class(uid)
                == InstanceAvailabilityNotificationServiceClass
            )

    def test_media_creation_uids(self):
        """Test that the Media Creation SOP Class UIDs work correctly."""
        for uid in _MEDIA_CREATION_CLASSES.values():
            assert uid_to_service_class(uid) == MediaCreationManagementServiceClass

    def test_media_storage_uids(self):
        """Test that the Media Storage SOP Class UIDs work correctly."""
        for uid in _MEDIA_STORAGE_CLASSES.values():
            assert uid_to_service_class(uid) == ServiceClass

    def test_non_patient_uids(self):
        """Test that the Non-Patient Object SOP Class UIDs work correctly."""
        for uid in _NON_PATIENT_OBJECT_CLASSES.values():
            assert uid_to_service_class(uid) == NonPatientObjectStorageServiceClass

    def test_print_uids(self):
        """Test that the Print SOP Class UIDs work correctly."""
        for uid in _PRINT_MANAGEMENT_CLASSES.values():
            assert uid_to_service_class(uid) == PrintManagementServiceClass

    def test_procedure_step_uids(self):
        """Test that the Procedure SOP Class UIDs work correctly."""
        for uid in _PROCEDURE_STEP_CLASSES.values():
            assert uid_to_service_class(uid) == ProcedureStepServiceClass

    def test_protocol_approval_uids(self):
        """Test that Protocol Approval SOP Class UIDs work correctly."""
        for uid in _PROTOCOL_APPROVAL_CLASSES.values():
            assert (
                uid_to_service_class(uid) == ProtocolApprovalQueryRetrieveServiceClass
            )

    def test_qr_uids(self):
        """Test that the QR SOP Class UIDs work correctly."""
        for uid in _QR_CLASSES.values():
            assert uid_to_service_class(uid) == QueryRetrieveServiceClass

    def test_relevant_patient_uids(self):
        """Test that the Relevant Patient SOP Class UIDs work correctly."""
        for uid in _RELEVANT_PATIENT_QUERY_CLASSES.values():
            assert (
                uid_to_service_class(uid) == RelevantPatientInformationQueryServiceClass
            )

    def test_rt_machine_uids(self):
        """Test that the RT Verification SOP Class UIDs work correctly."""
        for uid in _RT_MACHINE_VERIFICATION_CLASSES.values():
            assert uid_to_service_class(uid) == RTMachineVerificationServiceClass

    def test_storage_uids(self):
        """Test that the Storage SOP Class UIDs work correctly."""
        for uid in _STORAGE_CLASSES.values():
            assert uid_to_service_class(uid) == StorageServiceClass

    def test_storage_commitment_uids(self):
        """Test that the Storage Commitment SOP Class UIDs work correctly."""
        for uid in _STORAGE_COMMITMENT_CLASSES.values():
            assert uid_to_service_class(uid) == StorageCommitmentServiceClass

    def test_substance_admin_uids(self):
        """Test that the Substance Administration SOP Class UIDs work correctly."""
        for uid in _SUBSTANCE_ADMINISTRATION_CLASSES.values():
            assert uid_to_service_class(uid) == SubstanceAdministrationQueryServiceClass

    def test_ups_uids(self):
        """Test that the UPS SOP Class UIDs work correctly."""
        for uid in _UNIFIED_PROCEDURE_STEP_CLASSES.values():
            assert uid_to_service_class(uid) == UnifiedProcedureStepServiceClass

    def test_verification_uids(self):
        """Test that the Verification SOP Class UIDs work correctly."""
        for uid in _VERIFICATION_CLASSES.values():
            assert uid_to_service_class(uid) == VerificationServiceClass

    def test_unknown_uid(self):
        """Test that an unknown UID returns default service class."""
        assert uid_to_service_class("1.2.3") == ServiceClass


class TestSOPClass:
    """Tests for sop_class.SOPClass."""

    def test_app_logging_sop(self):
        assert ProceduralEventLogging == "1.2.840.10008.1.40"
        assert (
            ProceduralEventLogging.service_class == ApplicationEventLoggingServiceClass
        )

    def test_basic_worklist_sop(self):
        """Test a Basic Worklist Service SOP Class."""
        assert ModalityWorklistInformationFind == "1.2.840.10008.5.1.4.31"
        assert (
            ModalityWorklistInformationFind.service_class
            == BasicWorklistManagementServiceClass
        )

    def test_color_palette_sop(self):
        """Test a Color Palette Service SOP Class."""
        assert ColorPaletteInformationModelMove == "1.2.840.10008.5.1.4.39.3"
        assert (
            ColorPaletteInformationModelMove.service_class
            == ColorPaletteQueryRetrieveServiceClass
        )

    def test_defined_procedure_sop(self):
        """Test a Defined Procedure Protocol Service SOP Class."""
        assert (
            DefinedProcedureProtocolInformationModelFind == "1.2.840.10008.5.1.4.20.1"
        )
        assert (
            DefinedProcedureProtocolInformationModelFind.service_class
            == DefinedProcedureProtocolQueryRetrieveServiceClass
        )

    def test_display_sop(self):
        assert DisplaySystem == "1.2.840.10008.5.1.1.40"
        assert DisplaySystem.service_class == DisplaySystemManagementServiceClass

    def test_hanging_protocol_sop(self):
        """Test a Hanging Protocol Service SOP Class."""
        assert HangingProtocolInformationModelGet == "1.2.840.10008.5.1.4.38.4"
        assert (
            HangingProtocolInformationModelGet.service_class
            == HangingProtocolQueryRetrieveServiceClass
        )

    def test_implant_template_sop(self):
        """Test an Implant Template Service SOP Class."""
        assert ImplantTemplateGroupInformationModelFind == "1.2.840.10008.5.1.4.45.2"
        assert (
            ImplantTemplateGroupInformationModelFind.service_class
            == ImplantTemplateQueryRetrieveServiceClass
        )

    def test_instance_sop(self):
        assert InstanceAvailabilityNotification == "1.2.840.10008.5.1.4.33"
        assert (
            InstanceAvailabilityNotification.service_class
            == InstanceAvailabilityNotificationServiceClass
        )

    def test_media_creation_sop(self):
        assert MediaCreationManagement == "1.2.840.10008.5.1.1.33"
        assert (
            MediaCreationManagement.service_class == MediaCreationManagementServiceClass
        )

    def test_media_storage_sop(self):
        assert MediaStorageDirectoryStorage == "1.2.840.10008.1.3.10"
        assert MediaStorageDirectoryStorage.service_class == ServiceClass

    def test_non_patient_sop(self):
        """Test a Non-Patient Object Service SOP Class."""
        assert HangingProtocolStorage == "1.2.840.10008.5.1.4.38.1"
        assert (
            HangingProtocolStorage.service_class == NonPatientObjectStorageServiceClass
        )

    def test_print_sop(self):
        assert PrintJob == "1.2.840.10008.5.1.1.14"
        assert PrintJob.service_class == PrintManagementServiceClass

    def test_procedure_step_sop(self):
        assert ModalityPerformedProcedureStep == "1.2.840.10008.3.1.2.3.3"
        assert ModalityPerformedProcedureStep.service_class == ProcedureStepServiceClass

    def test_protocol_approval_sop(self):
        """Test an Protocol Approval Service SOP Class."""
        assert ProtocolApprovalInformationModelFind == "1.2.840.10008.5.1.4.1.1.200.4"
        assert (
            ProtocolApprovalInformationModelFind.service_class
            == ProtocolApprovalQueryRetrieveServiceClass
        )

    def test_qr_sop(self):
        """Test a Query/Retrieve Service SOP Class."""
        assert (
            StudyRootQueryRetrieveInformationModelFind == "1.2.840.10008.5.1.4.1.2.2.1"
        )
        assert (
            StudyRootQueryRetrieveInformationModelFind.service_class
            == QueryRetrieveServiceClass
        )

    def test_relevant_patient_info_sop(self):
        """Test a Relevant Patient Information Query Service SOP Class."""
        assert GeneralRelevantPatientInformationQuery == "1.2.840.10008.5.1.4.37.1"
        assert (
            GeneralRelevantPatientInformationQuery.service_class
            == RelevantPatientInformationQueryServiceClass
        )

    def test_rt_sop(self):
        assert RTConventionalMachineVerification == "1.2.840.10008.5.1.4.34.8"
        assert (
            RTConventionalMachineVerification.service_class
            == RTMachineVerificationServiceClass
        )

    def test_storage_sop(self):
        """Test a Storage Service SOP Class."""
        assert CTImageStorage == "1.2.840.10008.5.1.4.1.1.2"
        assert CTImageStorage.service_class == StorageServiceClass

    def test_storage_commitment_sop(self):
        assert StorageCommitmentPushModel == "1.2.840.10008.1.20.1"
        assert StorageCommitmentPushModel.service_class == StorageCommitmentServiceClass

    def test_substance_admin_sop(self):
        """Test s Substance Administration Query Service SOP Class."""
        assert ProductCharacteristicsQuery == "1.2.840.10008.5.1.4.41"
        assert (
            ProductCharacteristicsQuery.service_class
            == SubstanceAdministrationQueryServiceClass
        )

    def test_ups_sop(self):
        assert UnifiedProcedureStepPull == "1.2.840.10008.5.1.4.34.6.3"
        assert (
            UnifiedProcedureStepPull.service_class == UnifiedProcedureStepServiceClass
        )

    def test_verification_sop(self):
        """Test a Verification Service SOP Class."""
        assert Verification == "1.2.840.10008.1.1"
        assert Verification.service_class == VerificationServiceClass

    def test_uid_creation(self):
        """Test creating a new UIDSOPClass."""
        sop_class = SOPClass("1.2.3")
        sop_class._service_class = ServiceClass

        assert sop_class == "1.2.3"
        assert sop_class.service_class == ServiceClass

        sop_class_b = SOPClass(sop_class)
        assert sop_class == sop_class_b
        assert sop_class_b == "1.2.3"
        assert sop_class_b.service_class == ServiceClass
