"""
WRC Mainline validation rules.

This module contains data-driven validation rules for WRC mainline observations.
It replaces the repetitive if-elif validation logic with a more maintainable approach.
"""

from typing import Any, Dict, Union

from ....records.wrc.wrc_defects import WrcDefectRecords


class WrcMainlineValidationRules:
    """
    Data-driven validation rules for WRC mainline observations.

    This class provides static methods to validate different categories of defects
    based on their specific requirements.
    """

    @staticmethod
    def _get_field_value(values: Union[Dict[str, Any], Any], field_name: str) -> Any:
        """Helper method to get field value from either dict or model instance."""
        if hasattr(values, field_name):
            return getattr(values, field_name)
        else:
            return values.get(field_name)

    @staticmethod
    def validate_observation(values: Union[Dict[str, Any], Any]) -> None:
        """
        Validate a WRC mainline observation based on the defect code.

        Args:
            values: Pydantic model instance or dictionary containing the observation data

        Raises:
            ValueError: If validation fails
        """
        code = WrcMainlineValidationRules._get_field_value(values, "code")
        if not code:
            return
        code = WrcDefectRecords.from_abbreviation(code)

        # Dispatch to appropriate validation method based on defect category
        if code in WrcMainlineValidationRules._crack_defects:
            WrcMainlineValidationRules._validate_crack_defects(values, code)
        elif code in WrcMainlineValidationRules._fracture_defects:
            WrcMainlineValidationRules._validate_fracture_defects(values, code)
        elif code in WrcMainlineValidationRules._broken_hole_defects:
            WrcMainlineValidationRules._validate_broken_hole_defects(values, code)
        elif code in WrcMainlineValidationRules._joint_defects:
            WrcMainlineValidationRules._validate_joint_defects(values, code)
        elif code in WrcMainlineValidationRules._surface_damage_defects:
            WrcMainlineValidationRules._validate_surface_damage_defects(values, code)
        elif code in WrcMainlineValidationRules._deformed_defects:
            WrcMainlineValidationRules._validate_deformed_defects(values, code)
        elif code in WrcMainlineValidationRules._collapsed_defects:
            WrcMainlineValidationRules._validate_collapsed_defects(values, code)
        elif code in WrcMainlineValidationRules._lining_defects:
            WrcMainlineValidationRules._validate_lining_defects(values, code)
        elif code in WrcMainlineValidationRules._weld_failure_defects:
            WrcMainlineValidationRules._validate_weld_failure_defects(values, code)
        elif code in WrcMainlineValidationRules._point_repair_defects:
            WrcMainlineValidationRules._validate_point_repair_defects(values, code)
        elif code in WrcMainlineValidationRules._defective_repair_defects:
            WrcMainlineValidationRules._validate_defective_repair_defects(values, code)
        elif code in WrcMainlineValidationRules._brickwork_defects:
            WrcMainlineValidationRules._validate_brickwork_defects(values, code)
        elif code in WrcMainlineValidationRules._deposits_defects:
            WrcMainlineValidationRules._validate_deposits_defects(values, code)
        elif code in WrcMainlineValidationRules._ingress_defects:
            WrcMainlineValidationRules._validate_ingress_defects(values, code)
        elif code in WrcMainlineValidationRules._roots_defects:
            WrcMainlineValidationRules._validate_roots_defects(values, code)
        elif code in WrcMainlineValidationRules._infiltration_defects:
            WrcMainlineValidationRules._validate_infiltration_defects(values, code)
        elif code in WrcMainlineValidationRules._obstruction_defects:
            WrcMainlineValidationRules._validate_obstruction_defects(values, code)
        elif code in WrcMainlineValidationRules._connection_defects:
            WrcMainlineValidationRules._validate_connection_defects(values, code)
        elif code in WrcMainlineValidationRules._junction_defects:
            WrcMainlineValidationRules._validate_junction_defects(values, code)
        elif code in WrcMainlineValidationRules._sealing_defects:
            WrcMainlineValidationRules._validate_sealing_defects(values, code)
        elif code in WrcMainlineValidationRules._line_deviation_defects:
            WrcMainlineValidationRules._validate_line_deviation_defects(values, code)
        elif code in WrcMainlineValidationRules._change_defects:
            WrcMainlineValidationRules._validate_change_defects(values, code)
        elif code in WrcMainlineValidationRules._material_defects:
            WrcMainlineValidationRules._validate_material_defects(values, code)
        elif code in WrcMainlineValidationRules._node_type_defects:
            WrcMainlineValidationRules._validate_node_type_defects(values, code)
        elif code in WrcMainlineValidationRules._survey_defects:
            WrcMainlineValidationRules._validate_survey_defects(values, code)
        elif code in WrcMainlineValidationRules._vermin_defects:
            WrcMainlineValidationRules._validate_vermin_defects(values, code)
        elif code in WrcMainlineValidationRules._general_defects:
            WrcMainlineValidationRules._validate_general_defects(values, code)
        elif code in WrcMainlineValidationRules._flow_defects:
            WrcMainlineValidationRules._validate_flow_defects(values, code)
        elif code in WrcMainlineValidationRules._hazardous_defects:
            WrcMainlineValidationRules._validate_hazardous_defects(values, code)
        elif code in WrcMainlineValidationRules._vision_defects:
            WrcMainlineValidationRules._validate_vision_defects(values, code)
        elif code in WrcMainlineValidationRules._reference_defects:
            WrcMainlineValidationRules._validate_reference_defects(values, code)

    # Defect category mappings
    _crack_defects = {
        WrcDefectRecords.crack_longitudinal,
        WrcDefectRecords.crack_circumferential,
        WrcDefectRecords.crack_multiple,
        WrcDefectRecords.crack_radiates,
        WrcDefectRecords.crack_spiral,
    }

    _fracture_defects = {
        WrcDefectRecords.fracture_longitudinal,
        WrcDefectRecords.fracture_circumferential,
        WrcDefectRecords.fracture_multiple,
        WrcDefectRecords.fracture_spiral,
        WrcDefectRecords.fracture_radiates,
    }

    _broken_hole_defects = {
        WrcDefectRecords.broken,
        WrcDefectRecords.broken_soil_visible,
        WrcDefectRecords.broken_void_visible,
        WrcDefectRecords.hole,
        WrcDefectRecords.hole_soil_visible,
        WrcDefectRecords.hole_void_visible,
    }

    _joint_defects = {
        WrcDefectRecords.joint_displaced,
        WrcDefectRecords.joint_displaced_medium,
        WrcDefectRecords.joint_displaced_large,
        WrcDefectRecords.open_joint,
        WrcDefectRecords.open_joint_medium,
        WrcDefectRecords.open_joint_large,
    }

    _surface_damage_defects = {
        WrcDefectRecords.surface_damage_increased_roughness,
        WrcDefectRecords.surface_damage_spalling,
        WrcDefectRecords.surface_damage_internal_blister_or_bulge,
        WrcDefectRecords.surface_damage_aggregate_visible,
        WrcDefectRecords.surface_damage_aggregate_projecting_from_surface,
        WrcDefectRecords.surface_damage_reinforcement_visible,
        WrcDefectRecords.surface_damage_reinforcement_projecting_from_surface,
        WrcDefectRecords.surface_damage_reinforcement_corroded,
        WrcDefectRecords.surface_damage_corrosion_products,
        WrcDefectRecords.surface_damage_other_damage,
        WrcDefectRecords.surface_damage,
    }

    _deformed_defects = {
        WrcDefectRecords.deformed_drain_sewer,
        WrcDefectRecords.deformed_vertical,
        WrcDefectRecords.deformed_horizontal,
    }

    _collapsed_defects = {
        WrcDefectRecords.collapsed_brickwork_masonry,
        WrcDefectRecords.collapsed_drain_sewer,
    }

    _lining_defects = {
        WrcDefectRecords.lining_defect,
        WrcDefectRecords.lining_defect_blister_or_internal_bulge,
        WrcDefectRecords.lining_defect_lining_detached,
        WrcDefectRecords.lining_defect_discolored,
        WrcDefectRecords.lining_defect_defective_end,
        WrcDefectRecords.lining_defect_longitudinal_wrinkles,
        WrcDefectRecords.lining_defect_circumferential_wrinkling,
        WrcDefectRecords.lining_defect_spiral_wrinkling,
        WrcDefectRecords.lining_defect_complex_multiple_wrinkling,
        WrcDefectRecords.lining_defect_other,
        WrcDefectRecords.lining_defect_at_connection,
        WrcDefectRecords.lining_defect_external_bulge,
        WrcDefectRecords.lining_defect_end_not_sealed,
        WrcDefectRecords.lining_defect_separated_film,
        WrcDefectRecords.lining_defect_hole_in_lining,
        WrcDefectRecords.lining_defect_resin_missing,
        WrcDefectRecords.lining_defect_crack_or_split,
        WrcDefectRecords.lining_defect_circumferential_crack_or_split,
        WrcDefectRecords.lining_defect_spiral_crack_or_split,
        WrcDefectRecords.lining_defect_longitudinal_crack_or_split,
        WrcDefectRecords.lining_defect_complex_crack_or_split,
        WrcDefectRecords.lining_defect_soft_lining,
        WrcDefectRecords.lining_defect_separated_seam_cover,
    }

    _weld_failure_defects = {
        WrcDefectRecords.weld_failure_circumferential,
        WrcDefectRecords.weld_failure_longitudinal,
        WrcDefectRecords.weld_failure_spiral,
    }

    _point_repair_defects = {
        WrcDefectRecords.point_repair_pipe_replaced,
        WrcDefectRecords.point_repair_localised_lining,
        WrcDefectRecords.point_repair_injected_mortar,
        WrcDefectRecords.point_repair_other_injected_sealing_material,
        WrcDefectRecords.point_repair_hole_repaired,
        WrcDefectRecords.point_repair_other_repair_to_connection,
        WrcDefectRecords.point_repair_localised_lining_of_connection,
        WrcDefectRecords.point_repair_other,
    }

    _defective_repair_defects = {
        WrcDefectRecords.defective_repair_part_of_wall_missing,
        WrcDefectRecords.defective_repair_crack_in_material,
        WrcDefectRecords.defective_repair_hole_in_material,
        WrcDefectRecords.defective_repair_missing_repair_material,
        WrcDefectRecords.defective_repair_separation_from_host_pipe,
        WrcDefectRecords.defective_repair_excess_material_obstruction,
        WrcDefectRecords.defective_repair_other,
    }

    _brickwork_defects = {
        WrcDefectRecords.displaced_brick,
        WrcDefectRecords.missing_brick,
        WrcDefectRecords.dropped_invert,
        WrcDefectRecords.mortar_missing,
        WrcDefectRecords.mortar_missing_slight,
        WrcDefectRecords.mortar_missing_medium,
        WrcDefectRecords.mortar_missing_total,
    }

    _deposits_defects = {
        WrcDefectRecords.attached_deposits_encrustation,
        WrcDefectRecords.attached_deposits_grease,
        WrcDefectRecords.attached_deposits_fouling,
        WrcDefectRecords.attached_deposits_other,
        WrcDefectRecords.settled_deposits_hard_or_compacted,
        WrcDefectRecords.settled_deposits_fine,
        WrcDefectRecords.settled_deposits_coarse,
        WrcDefectRecords.settled_deposits_other,
    }

    _ingress_defects = {
        WrcDefectRecords.ingress_of_soil_fine_material,
        WrcDefectRecords.ingress_of_soil_gravel,
        WrcDefectRecords.ingress_of_soil_other,
        WrcDefectRecords.ingress_of_soil,
        WrcDefectRecords.ingress_of_soil_sand,
        WrcDefectRecords.ingress_of_soil_peat,
    }

    _roots_defects = {
        WrcDefectRecords.roots,
        WrcDefectRecords.roots_fine,
        WrcDefectRecords.roots_tap,
        WrcDefectRecords.roots_mass,
    }

    _infiltration_defects = {
        WrcDefectRecords.infiltration,
        WrcDefectRecords.infiltration_seeping,
        WrcDefectRecords.infiltration_dripping,
        WrcDefectRecords.infiltration_running,
        WrcDefectRecords.infiltration_gushing,
        WrcDefectRecords.exfiltration,
    }

    _obstruction_defects = {
        WrcDefectRecords.other_obstacles_brick_or_masonry_in_invert,
        WrcDefectRecords.other_obstacles_pipe_material_in_invert,
        WrcDefectRecords.other_obstacles_obstacle_protruding_through_wall,
        WrcDefectRecords.other_obstacles_other_object_in_invert,
        WrcDefectRecords.other_obstacles_through_connection_junction,
        WrcDefectRecords.other_obstacles_external_pipe_or_cable,
        WrcDefectRecords.other_obstacles_obstacle_built_into_structure,
        WrcDefectRecords.other_obstacles_other,
        WrcDefectRecords.obstruction,
    }

    _connection_defects = {
        WrcDefectRecords.connection,
        WrcDefectRecords.connection_c,
        WrcDefectRecords.defective_connection,
        WrcDefectRecords.defective_connection_intruding,
        WrcDefectRecords.defective_connection_connecting_pipe_blocked,
        WrcDefectRecords.defective_connection_position_incorrect,
        WrcDefectRecords.defective_connection_connecting_pipe_damaged,
        WrcDefectRecords.defective_connection_other,
    }

    _junction_defects = {
        WrcDefectRecords.junction,
        WrcDefectRecords.junction_closed,
        WrcDefectRecords.defective_junction,
        WrcDefectRecords.defective_junction_position_incorrect,
        WrcDefectRecords.defective_junction_connecting_pipe_damaged,
        WrcDefectRecords.defective_junction_connecting_pipe_blocked,
        WrcDefectRecords.defective_junction_other,
    }

    _sealing_defects = {
        WrcDefectRecords.sealing_ring_intruding,
        WrcDefectRecords.sealing_ring_intruding_and_broken,
        WrcDefectRecords.other_sealant_intruding,
    }

    _line_deviation_defects = {
        WrcDefectRecords.line_deviates_left,
        WrcDefectRecords.line_deviates_right,
        WrcDefectRecords.line_deviates_up,
        WrcDefectRecords.line_deviates_down,
    }

    _change_defects = {
        WrcDefectRecords.change_of_shape,
        WrcDefectRecords.change_of_material,
        WrcDefectRecords.change_of_lining,
        WrcDefectRecords.change_of_pipe_length,
    }

    _material_defects = {
        WrcDefectRecords.porous_pipe_material,
        WrcDefectRecords.soil_visible,
        WrcDefectRecords.void_visible,
        WrcDefectRecords.water_level,
        WrcDefectRecords.water_level_clear_water,
        WrcDefectRecords.water_level_turbid_water,
    }

    _node_type_defects = {
        WrcDefectRecords.start_node_type_manhole,
        WrcDefectRecords.start_node_type_inspection_chamber,
        WrcDefectRecords.start_node_type_rodding_eye,
        WrcDefectRecords.start_node_type_lamphole,
        WrcDefectRecords.start_node_type_outfall,
        WrcDefectRecords.start_node_type_running_trap,
        WrcDefectRecords.start_node_type_buchan_trap,
        WrcDefectRecords.start_node_type_catchpit,
        WrcDefectRecords.start_node_type_gully,
        WrcDefectRecords.start_node_type_oil_separator,
        WrcDefectRecords.start_node_type_soakaway,
        WrcDefectRecords.start_node_type_winser_trap,
        WrcDefectRecords.start_node_type_major_connection_without_manhole,
        WrcDefectRecords.start_node_type_other_special_chamber,
        WrcDefectRecords.finish_node_type_manhole,
        WrcDefectRecords.finish_node_type_inspection_chamber,
        WrcDefectRecords.finish_node_type_rodding_eye,
        WrcDefectRecords.finish_node_type_lamphole,
        WrcDefectRecords.finish_node_type_outfall,
        WrcDefectRecords.finish_node_type_running_trap,
        WrcDefectRecords.finish_node_type_buchan_trap,
        WrcDefectRecords.finish_node_type_catchpit,
        WrcDefectRecords.finish_node_type_gully,
        WrcDefectRecords.finish_node_type_oil_separator,
        WrcDefectRecords.finish_node_type_soakaway,
        WrcDefectRecords.finish_node_type_winser_trap,
        WrcDefectRecords.finish_node_type_major_connection_without_manhole,
        WrcDefectRecords.finish_node_type_other_special_chamber,
    }

    _survey_defects = {
        WrcDefectRecords.survey_abandoned,
    }

    _vermin_defects = {
        WrcDefectRecords.vermin,
        WrcDefectRecords.vermin_rat,
        WrcDefectRecords.vermin_rats_observed_in_connection,
        WrcDefectRecords.vermin_rats_observed_in_open_joint,
        WrcDefectRecords.vermin_other,
    }

    _general_defects = {
        WrcDefectRecords.general_photograph,
        WrcDefectRecords.general_remark,
    }

    _flow_defects = {
        WrcDefectRecords.flow_from_incoming_pipe,
        WrcDefectRecords.flow_from_incoming_pipe_clear,
        WrcDefectRecords.flow_from_incoming_pipe_wrong_clear_flow,
        WrcDefectRecords.flow_from_incoming_pipe_turbid,
        WrcDefectRecords.flow_from_incoming_pipe_wrong_foul_flow,
    }

    _hazardous_defects = {
        WrcDefectRecords.hazardous_atmosphere_oxygen_deficiency,
        WrcDefectRecords.hazardous_atmosphere_hydrogen_sulphide,
        WrcDefectRecords.hazardous_atmosphere_methane,
        WrcDefectRecords.hazardous_atmosphere_other,
    }

    _vision_defects = {
        WrcDefectRecords.loss_of_vision,
        WrcDefectRecords.loss_of_vision_camera_underwater,
        WrcDefectRecords.loss_of_vision_silt,
        WrcDefectRecords.loss_of_vision_stream,
        WrcDefectRecords.loss_of_vision_other,
    }

    _reference_defects = {
        WrcDefectRecords.video_volume_reference,
        WrcDefectRecords.photograph_volume_reference,
    }

    # Validation methods for each category
    @staticmethod
    def _validate_crack_defects(values, code) -> None:
        """Validate crack defects."""
        if not code:
            return

        distance = WrcMainlineValidationRules._get_field_value(values, "distance")
        circumferential_location_from = WrcMainlineValidationRules._get_field_value(values, "circumferential_location_from")
        circumferential_location_to = WrcMainlineValidationRules._get_field_value(values, "circumferential_location_to")
        required_fields = []

        # All crack defects require distance and circumferential_location_from
        if distance is None:
            required_fields.append("distance")
        if circumferential_location_from is None:
            required_fields.append("circumferential_location_from")

        # Some crack defects also require circumferential_location_to
        if code in {
            WrcDefectRecords.crack_circumferential,
            WrcDefectRecords.crack_multiple,
            WrcDefectRecords.crack_spiral,
        }:
            if circumferential_location_to is None:
                required_fields.append("circumferential_location_to")

        if required_fields:
            raise ValueError(f"{', '.join(required_fields)} is required for {code.full_name}")

    @staticmethod
    def _validate_fracture_defects(values, code) -> None:
        """Validate fracture defects."""
        if not code:
            return

        distance = WrcMainlineValidationRules._get_field_value(values, "distance")
        circumferential_location_from = WrcMainlineValidationRules._get_field_value(values, "circumferential_location_from")
        circumferential_location_to = WrcMainlineValidationRules._get_field_value(values, "circumferential_location_to")
        required_fields = []
        # All fracture defects require distance and circumferential_location_from
        if distance is None:
            required_fields.append("distance")
        if circumferential_location_from is None:
            required_fields.append("circumferential_location_from")

        # Some fracture defects also require circumferential_location_to
        if code in {
            WrcDefectRecords.fracture_circumferential,
            WrcDefectRecords.fracture_multiple,
            WrcDefectRecords.fracture_spiral,
        }:
            if circumferential_location_to is None:
                required_fields.append("circumferential_location_to")
        if required_fields:
            raise ValueError(f"{', '.join(required_fields)} is required for {code.full_name}")

    @staticmethod
    def _validate_broken_hole_defects(values, code) -> None:
        """Validate broken and hole defects."""
        if not code:
            return

        distance = WrcMainlineValidationRules._get_field_value(values, "distance")
        circumferential_location_from = WrcMainlineValidationRules._get_field_value(values, "circumferential_location_from")
        required_fields = []

        # All broken/hole defects require distance and circumferential_location_from
        if distance is None:
            required_fields.append("distance")
        if circumferential_location_from is None:
            required_fields.append("circumferential_location_from")

        if required_fields:
            raise ValueError(f"{', '.join(required_fields)} is required for {code.full_name}")

    @staticmethod
    def _validate_joint_defects(values, code) -> None:
        """Validate joint defects."""
        if not code:
            return

        distance = WrcMainlineValidationRules._get_field_value(values, "distance")
        band = WrcMainlineValidationRules._get_field_value(values, "band")
        required_fields = []

        # All joint defects require distance and band
        if distance is None:
            required_fields.append("distance")
        if code in {
            WrcDefectRecords.joint_displaced_medium,
            WrcDefectRecords.joint_displaced_large,
            WrcDefectRecords.open_joint_medium,
            WrcDefectRecords.open_joint_large,
        }:
            if band is None:
                required_fields.append("band")

        if required_fields:
            raise ValueError(f"{', '.join(required_fields)} is required for {code.full_name}")

    @staticmethod
    def _validate_surface_damage_defects(values, code) -> None:
        """Validate surface damage defects."""
        if not code:
            return

        distance = WrcMainlineValidationRules._get_field_value(values, "distance")
        circumferential_location_from = WrcMainlineValidationRules._get_field_value(values, "circumferential_location_from")
        remarks = WrcMainlineValidationRules._get_field_value(values, "remarks")
        required_fields = []

        # All surface damage defects require distance and circumferential_location_from
        if distance is None:
            required_fields.append("distance")
        if circumferential_location_from is None:
            required_fields.append("circumferential_location_from")
        if code in {
            WrcDefectRecords.surface_damage_other_damage,
        }:
            if remarks is None:
                required_fields.append("remarks")

        if required_fields:
            raise ValueError(f"{', '.join(required_fields)} is required for {code.full_name}")

    @staticmethod
    def _validate_deformed_defects(values, code) -> None:
        """Validate deformed defects."""
        if not code:
            return

        distance = WrcMainlineValidationRules._get_field_value(values, "distance")
        value_defect_percent = WrcMainlineValidationRules._get_field_value(values, "value_defect_percent")
        required_fields = []

        # All deformed defects require distance and value_defect_percent
        if distance is None:
            required_fields.append("distance")
        if value_defect_percent is None:
            required_fields.append("value_defect_percent")

        if required_fields:
            raise ValueError(f"{', '.join(required_fields)} is required for {code.full_name}")

    @staticmethod
    def _validate_collapsed_defects(values, code) -> None:
        """Validate collapsed defects."""
        if not code:
            return

        distance = WrcMainlineValidationRules._get_field_value(values, "distance")
        value_defect_percent = WrcMainlineValidationRules._get_field_value(values, "value_defect_percent")
        required_fields = []

        # All collapsed defects require distance and value_defect_percent
        if distance is None:
            required_fields.append("distance")
        if value_defect_percent is None:
            required_fields.append("value_defect_percent")

        if required_fields:
            raise ValueError(f"{', '.join(required_fields)} is required for {code.full_name}")

    @staticmethod
    def _validate_lining_defects(values, code) -> None:
        """Validate lining defects."""
        if not code:
            return

        distance = WrcMainlineValidationRules._get_field_value(values, "distance")
        value_defect_percent = WrcMainlineValidationRules._get_field_value(values, "value_defect_percent")
        circumferential_location_from = WrcMainlineValidationRules._get_field_value(values, "circumferential_location_from")
        circumferential_location_to = WrcMainlineValidationRules._get_field_value(values, "circumferential_location_to")
        remarks = WrcMainlineValidationRules._get_field_value(values, "remarks")
        required_fields = []

        # All lining defects require distance and circumferential_location_from
        if distance is None:
            required_fields.append("distance")
        if circumferential_location_from is None:
            required_fields.append("circumferential_location_from")
        if code in {
            WrcDefectRecords.lining_defect_separated_film,
            WrcDefectRecords.lining_defect_end_not_sealed,
            WrcDefectRecords.lining_defect_other,
            WrcDefectRecords.lining_defect_complex_multiple_wrinkling,
            WrcDefectRecords.lining_defect_spiral_wrinkling,
            WrcDefectRecords.lining_defect_longitudinal_wrinkles,
            WrcDefectRecords.lining_defect_circumferential_wrinkling,
            WrcDefectRecords.lining_defect_defective_end,
            WrcDefectRecords.lining_defect_lining_detached,
            WrcDefectRecords.lining_defect_discolored,
            WrcDefectRecords.lining_defect_blister_or_internal_bulge,
        }:
            if value_defect_percent is None:
                required_fields.append("value_defect_percent")
        if code in {
            WrcDefectRecords.lining_defect_other,
        }:
            if remarks is None:
                required_fields.append("remarks")

        if code in {
            WrcDefectRecords.lining_defect_circumferential_crack_or_split,
            WrcDefectRecords.lining_defect_spiral_crack_or_split,
            WrcDefectRecords.lining_defect_complex_crack_or_split,
            WrcDefectRecords.lining_defect_separated_film,
            WrcDefectRecords.lining_defect_separated_seam_cover,
            WrcDefectRecords.lining_defect_complex_multiple_wrinkling,
            WrcDefectRecords.lining_defect_spiral_wrinkling,
            WrcDefectRecords.lining_defect_circumferential_wrinkling,
        }:
            if circumferential_location_to is None:
                required_fields.append("circumferential_location_to")
        if required_fields:
            raise ValueError(f"{', '.join(required_fields)} is required for {code.full_name}")

    @staticmethod
    def _validate_weld_failure_defects(values, code) -> None:
        """Validate weld failure defects."""
        if not code:
            return

        distance = WrcMainlineValidationRules._get_field_value(values, "distance")
        circumferential_location_from = WrcMainlineValidationRules._get_field_value(values, "circumferential_location_from")
        circumferential_location_to = WrcMainlineValidationRules._get_field_value(values, "circumferential_location_to")
        required_fields = []

        # All weld failure defects require distance and circumferential_location_from
        if distance is None:
            required_fields.append("distance")
        if circumferential_location_from is None:
            required_fields.append("circumferential_location_from")
        if code in {
            WrcDefectRecords.weld_failure_circumferential,
            WrcDefectRecords.weld_failure_spiral,
        }:
            if circumferential_location_to is None:
                required_fields.append("circumferential_location_to")

        if required_fields:
            raise ValueError(f"{', '.join(required_fields)} is required for {code.full_name}")

    @staticmethod
    def _validate_point_repair_defects(values, code) -> None:
        """Validate point repair defects."""
        if not code:
            return

        distance = WrcMainlineValidationRules._get_field_value(values, "distance")
        circumferential_location_from = WrcMainlineValidationRules._get_field_value(values, "circumferential_location_from")
        circumferential_location_to = WrcMainlineValidationRules._get_field_value(values, "circumferential_location_to")
        remarks = WrcMainlineValidationRules._get_field_value(values, "remarks")
        required_fields = []

        # All point repair defects require distance and circumferential_location_from
        if distance is None:
            required_fields.append("distance")
        if circumferential_location_from is None:
            required_fields.append("circumferential_location_from")
        if code in {
            WrcDefectRecords.point_repair_pipe_replaced,
            WrcDefectRecords.point_repair_localised_lining,
        }:
            if circumferential_location_to is None:
                required_fields.append("circumferential_location_to")
        if code in {
            WrcDefectRecords.point_repair_other,
            WrcDefectRecords.point_repair_other_repair_to_connection,
        }:
            if remarks is None:
                required_fields.append("remarks")

        if required_fields:
            raise ValueError(f"{', '.join(required_fields)} is required for {code.full_name}")

    @staticmethod
    def _validate_defective_repair_defects(values, code) -> None:
        """Validate defective repair defects."""
        if not code:
            return

        distance = WrcMainlineValidationRules._get_field_value(values, "distance")
        value_defect_percent = WrcMainlineValidationRules._get_field_value(values, "value_defect_percent")
        circumferential_location_from = WrcMainlineValidationRules._get_field_value(values, "circumferential_location_from")
        remarks = WrcMainlineValidationRules._get_field_value(values, "remarks")
        required_fields = []

        # All defective repair defects require distance and circumferential_location_from
        if distance is None:
            required_fields.append("distance")
        if circumferential_location_from is None:
            required_fields.append("circumferential_location_from")
        if code in {
            WrcDefectRecords.defective_repair_separation_from_host_pipe,
            WrcDefectRecords.defective_repair_excess_material_obstruction,
        }:
            if value_defect_percent is None:
                required_fields.append("value_defect_percent")
        if code in {
            WrcDefectRecords.defective_repair_other,
        }:
            if remarks is None:
                required_fields.append("remarks")

        if required_fields:
            raise ValueError(f"{', '.join(required_fields)} is required for {code.full_name}")

    @staticmethod
    def _validate_brickwork_defects(values, code) -> None:
        """Validate brickwork defects."""
        if not code:
            return

        distance = WrcMainlineValidationRules._get_field_value(values, "distance")
        circumferential_location_from = WrcMainlineValidationRules._get_field_value(values, "circumferential_location_from")
        required_fields = []

        # All brickwork defects require distance and circumferential_location_from
        if distance is None:
            required_fields.append("distance")
        if circumferential_location_from is None:
            required_fields.append("circumferential_location_from")

        if required_fields:
            raise ValueError(f"{', '.join(required_fields)} is required for {code.full_name}")

    @staticmethod
    def _validate_deposits_defects(values, code) -> None:
        """Validate deposits defects."""
        if not code:
            return

        distance = WrcMainlineValidationRules._get_field_value(values, "distance")
        value_defect_percent = WrcMainlineValidationRules._get_field_value(values, "value_defect_percent")
        circumferential_location_from = WrcMainlineValidationRules._get_field_value(values, "circumferential_location_from")
        remarks = WrcMainlineValidationRules._get_field_value(values, "remarks")
        required_fields = []

        # All deposits defects require distance and circumferential_location_from
        if distance is None:
            required_fields.append("distance")
        if value_defect_percent is None:
            required_fields.append("value_defect_percent")
        if code in {
            WrcDefectRecords.attached_deposits_encrustation,
            WrcDefectRecords.attached_deposits_grease,
            WrcDefectRecords.attached_deposits_fouling,
            WrcDefectRecords.attached_deposits_other,
        }:
            if circumferential_location_from is None:
                required_fields.append("circumferential_location_from")
        if code in {
            WrcDefectRecords.attached_deposits_other,
            WrcDefectRecords.settled_deposits_other,
        }:
            if remarks is None:
                required_fields.append("remarks")

        if required_fields:
            raise ValueError(f"{', '.join(required_fields)} is required for {code.full_name}")

    @staticmethod
    def _validate_ingress_defects(values, code) -> None:
        """Validate ingress defects."""
        if not code:
            return

        distance = WrcMainlineValidationRules._get_field_value(values, "distance")
        circumferential_location_from = WrcMainlineValidationRules._get_field_value(values, "circumferential_location_from")
        value_defect_percent = WrcMainlineValidationRules._get_field_value(values, "value_defect_percent")
        remarks = WrcMainlineValidationRules._get_field_value(values, "remarks")
        required_fields = []

        # All ingress defects require distance and value_defect_percent
        if distance is None:
            required_fields.append("distance")
        if value_defect_percent is None:
            required_fields.append("value_defect_percent")
        if circumferential_location_from is None:
            required_fields.append("circumferential_location_from")
        if code in {
            WrcDefectRecords.ingress_of_soil_other,
        }:
            if remarks is None:
                required_fields.append("remarks")

        if required_fields:
            raise ValueError(f"{', '.join(required_fields)} is required for {code.full_name}")

    @staticmethod
    def _validate_roots_defects(values, code) -> None:
        """Validate roots defects."""
        if not code:
            return

        distance = WrcMainlineValidationRules._get_field_value(values, "distance")
        value_defect_percent = WrcMainlineValidationRules._get_field_value(values, "value_defect_percent")
        required_fields = []

        # All roots defects require distance and value_defect_percent
        if distance is None:
            required_fields.append("distance")
        if value_defect_percent is None:
            required_fields.append("value_defect_percent")

        if required_fields:
            raise ValueError(f"{', '.join(required_fields)} is required for {code.full_name}")

    @staticmethod
    def _validate_infiltration_defects(values, code) -> None:
        """Validate infiltration defects."""
        if not code:
            return

        distance = WrcMainlineValidationRules._get_field_value(values, "distance")
        circumferential_location_from = WrcMainlineValidationRules._get_field_value(values, "circumferential_location_from")
        required_fields = []

        # All infiltration defects require distance and circumferential_location_from
        if distance is None:
            required_fields.append("distance")
        if circumferential_location_from is None:
            required_fields.append("circumferential_location_from")

        if required_fields:
            raise ValueError(f"{', '.join(required_fields)} is required for {code.full_name}")

    @staticmethod
    def _validate_obstruction_defects(values, code) -> None:
        """Validate obstruction defects."""
        if not code:
            return

        distance = WrcMainlineValidationRules._get_field_value(values, "distance")
        value_defect_percent = WrcMainlineValidationRules._get_field_value(values, "value_defect_percent")
        circumferential_location_from = WrcMainlineValidationRules._get_field_value(values, "circumferential_location_from")
        remarks = WrcMainlineValidationRules._get_field_value(values, "remarks")
        required_fields = []

        # All obstruction defects require distance and value_defect_percent
        if distance is None:
            required_fields.append("distance")
        if value_defect_percent is None:
            required_fields.append("value_defect_percent")
        if circumferential_location_from is None:
            required_fields.append("circumferential_location_from")
        if code in {
            WrcDefectRecords.other_obstacles_other,
            WrcDefectRecords.other_obstacles_other_object_in_invert,
            WrcDefectRecords.other_obstacles_external_pipe_or_cable,
            WrcDefectRecords.other_obstacles_obstacle_built_into_structure,
        }:
            if remarks is None:
                required_fields.append("remarks")

        if required_fields:
            raise ValueError(f"{', '.join(required_fields)} is required for {code.full_name}")

    @staticmethod
    def _validate_connection_defects(values, code) -> None:
        """Validate connection defects."""
        if not code:
            return

        distance = WrcMainlineValidationRules._get_field_value(values, "distance")
        value_defect_percent = WrcMainlineValidationRules._get_field_value(values, "value_defect_percent")
        circumferential_location_from = WrcMainlineValidationRules._get_field_value(values, "circumferential_location_from")
        remarks = WrcMainlineValidationRules._get_field_value(values, "remarks")
        required_fields = []

        # All connection defects require distance and circumferential_location_from
        if distance is None:
            required_fields.append("distance")
        if circumferential_location_from is None:
            required_fields.append("circumferential_location_from")
        if code in {
            WrcDefectRecords.defective_connection_intruding,
        }:
            if value_defect_percent is None:
                required_fields.append("value_defect_percent")
        if code in {
            WrcDefectRecords.defective_connection_other,
        }:
            if remarks is None:
                required_fields.append("remarks")

        if required_fields:
            raise ValueError(f"{', '.join(required_fields)} is required for {code.full_name}")

    @staticmethod
    def _validate_junction_defects(values, code) -> None:
        """Validate junction defects."""
        if not code:
            return

        distance = WrcMainlineValidationRules._get_field_value(values, "distance")
        circumferential_location_from = WrcMainlineValidationRules._get_field_value(values, "circumferential_location_from")
        remarks = WrcMainlineValidationRules._get_field_value(values, "remarks")
        required_fields = []

        # All junction defects require distance and circumferential_location_from
        if distance is None:
            required_fields.append("distance")
        if circumferential_location_from is None:
            required_fields.append("circumferential_location_from")
        if code in {
            WrcDefectRecords.defective_junction_other,
        }:
            if remarks is None:
                required_fields.append("remarks")

        if required_fields:
            raise ValueError(f"{', '.join(required_fields)} is required for {code.full_name}")

    @staticmethod
    def _validate_sealing_defects(values, code) -> None:
        """Validate sealing defects."""
        if not code:
            return

        distance = WrcMainlineValidationRules._get_field_value(values, "distance")
        value_defect_percent = WrcMainlineValidationRules._get_field_value(values, "value_defect_percent")
        circumferential_location_from = WrcMainlineValidationRules._get_field_value(values, "circumferential_location_from")
        remarks = WrcMainlineValidationRules._get_field_value(values, "remarks")
        required_fields = []

        # All sealing defects require distance, value_defect_percent and circumferential_location_from
        if distance is None:
            required_fields.append("distance")
        if value_defect_percent is None:
            required_fields.append("value_defect_percent")
        if circumferential_location_from is None:
            required_fields.append("circumferential_location_from")
        if code in {
            WrcDefectRecords.other_sealant_intruding,
        }:
            if remarks is None:
                required_fields.append("remarks")

        if required_fields:
            raise ValueError(f"{', '.join(required_fields)} is required for {code.full_name}")

    @staticmethod
    def _validate_line_deviation_defects(values, code) -> None:
        """Validate line deviation defects."""
        if not code:
            return

        distance = WrcMainlineValidationRules._get_field_value(values, "distance")
        value_defect_percent = WrcMainlineValidationRules._get_field_value(values, "value_defect_percent")
        required_fields = []

        # All line deviation defects require distance and value_defect_percent
        if distance is None:
            required_fields.append("distance")
        if value_defect_percent is None:
            required_fields.append("value_defect_percent")

        if required_fields:
            raise ValueError(f"{', '.join(required_fields)} is required for {code.full_name}")

    @staticmethod
    def _validate_change_defects(values, code) -> None:
        """Validate change defects."""
        if not code:
            return

        distance = WrcMainlineValidationRules._get_field_value(values, "distance")
        material = WrcMainlineValidationRules._get_field_value(values, "material")
        value_1st_dimension = WrcMainlineValidationRules._get_field_value(values, "value_1st_dimension")
        required_fields = []

        # All change defects require distance
        if distance is None:
            required_fields.append("distance")
        if code in {
            WrcDefectRecords.change_of_shape,
            WrcDefectRecords.change_of_pipe_length,
        }:
            if value_1st_dimension is None:
                required_fields.append("value_1st_dimension")
        if code in {
            WrcDefectRecords.change_of_lining,
            WrcDefectRecords.change_of_material,
        }:
            if material is None:
                required_fields.append("material")

        if required_fields:
            raise ValueError(f"{', '.join(required_fields)} is required for {code.full_name}")

    @staticmethod
    def _validate_material_defects(values, code) -> None:
        """Validate material defects."""
        if not code:
            return

        distance = WrcMainlineValidationRules._get_field_value(values, "distance")
        value_defect_percent = WrcMainlineValidationRules._get_field_value(values, "value_defect_percent")
        circumferential_location_from = WrcMainlineValidationRules._get_field_value(values, "circumferential_location_from")
        required_fields = []

        # All obstruction defects require distance and value_defect_percent
        if distance is None:
            required_fields.append("distance")
        if code in {
            WrcDefectRecords.water_level,
            WrcDefectRecords.water_level_clear_water,
            WrcDefectRecords.water_level_turbid_water,
        }:
            if value_defect_percent is None:
                required_fields.append("value_defect_percent")
        if code in {
            WrcDefectRecords.porous_pipe_material,
        }:
            if circumferential_location_from is None:
                required_fields.append("circumferential_location_from")

        if required_fields:
            raise ValueError(f"{', '.join(required_fields)} is required for {code.full_name}")

    @staticmethod
    def _validate_node_type_defects(values, code) -> None:
        """Validate node type defects."""
        if not code:
            return

        distance = WrcMainlineValidationRules._get_field_value(values, "distance")
        value_1st_dimension = WrcMainlineValidationRules._get_field_value(values, "value_1st_dimension")
        remarks = WrcMainlineValidationRules._get_field_value(values, "remarks")
        required_fields = []

        # All node type defects require distance
        if distance is None:
            required_fields.append("distance")
        if value_1st_dimension is None:
            required_fields.append("value_1st_dimension")

        if code in {
            WrcDefectRecords.start_node_type_other_special_chamber,
            WrcDefectRecords.finish_node_type_other_special_chamber,
        }:
            if remarks is None:
                required_fields.append("remarks")
        if required_fields:
            raise ValueError(f"{', '.join(required_fields)} is required for {code.full_name}")

    @staticmethod
    def _validate_survey_defects(values, code) -> None:
        """Validate survey defects."""
        if not code:
            return

        distance = WrcMainlineValidationRules._get_field_value(values, "distance")
        remarks = WrcMainlineValidationRules._get_field_value(values, "remarks")
        required_fields = []

        # All survey defects require distance and remarks
        if distance is None:
            required_fields.append("distance")
        if remarks is None:
            required_fields.append("remarks")
        if required_fields:
            raise ValueError(f"{', '.join(required_fields)} is required for {code.full_name}")

    @staticmethod
    def _validate_vermin_defects(values, code) -> None:
        """Validate vermin defects."""
        if not code:
            return
        distance = WrcMainlineValidationRules._get_field_value(values, "distance")
        remarks = WrcMainlineValidationRules._get_field_value(values, "remarks")
        required_fields = []
        # All vermin defects require distance
        if distance is None:
            required_fields.append("distance")
        if code in {
            WrcDefectRecords.vermin_other,
        }:
            if remarks is None:
                required_fields.append("remarks")
        if required_fields:
            raise ValueError(f"{', '.join(required_fields)} is required for {code.full_name}")

    @staticmethod
    def _validate_general_defects(values, code) -> None:
        """Validate general defects."""
        if not code:
            return
        distance = WrcMainlineValidationRules._get_field_value(values, "distance")
        remarks = WrcMainlineValidationRules._get_field_value(values, "remarks")
        required_fields = []

        # All general defects require distance
        if distance is None:
            required_fields.append("distance")
        if code in {
            WrcDefectRecords.general_remark,
        }:
            if remarks is None:
                required_fields.append("remarks")
        if required_fields:
            raise ValueError(f"{', '.join(required_fields)} is required for {code.full_name}")

    @staticmethod
    def _validate_flow_defects(values, code) -> None:
        """Validate flow defects."""
        if not code:
            return
        distance = WrcMainlineValidationRules._get_field_value(values, "distance")
        value_defect_percent = WrcMainlineValidationRules._get_field_value(values, "value_defect_percent")
        circumferential_location_from = WrcMainlineValidationRules._get_field_value(values, "circumferential_location_from")
        required_fields = []

        # All flow defects require distance and value_defect_percent and circumferential_location_from
        if distance is None:
            required_fields.append("distance")
        if value_defect_percent is None:
            required_fields.append("value_defect_percent")
        if circumferential_location_from is None:
            required_fields.append("circumferential_location_from")
        if required_fields:
            raise ValueError(f"{', '.join(required_fields)} is required for {code.full_name}")

    @staticmethod
    def _validate_hazardous_defects(values, code) -> None:
        """Validate hazardous defects."""
        if not code:
            return
        distance = WrcMainlineValidationRules._get_field_value(values, "distance")
        remarks = WrcMainlineValidationRules._get_field_value(values, "remarks")
        required_fields = []

        # All hazardous defects require distance
        if distance is None:
            required_fields.append("distance")
        if code in {
            WrcDefectRecords.hazardous_atmosphere_other,
        }:
            if remarks is None:
                required_fields.append("remarks")
        if required_fields:
            raise ValueError(f"{', '.join(required_fields)} is required for {code.full_name}")

    @staticmethod
    def _validate_vision_defects(values, code) -> None:
        """Validate vision defects."""
        if not code:
            return
        distance = WrcMainlineValidationRules._get_field_value(values, "distance")
        remarks = WrcMainlineValidationRules._get_field_value(values, "remarks")
        required_fields = []

        # All hazardous defects require distance
        if distance is None:
            required_fields.append("distance")
        if code in {
            WrcDefectRecords.loss_of_vision_other,
        }:
            if remarks is None:
                required_fields.append("remarks")
        if required_fields:
            raise ValueError(f"{', '.join(required_fields)} is required for {code.full_name}")

    @staticmethod
    def _validate_reference_defects(values, code) -> None:
        """Validate reference defects."""
        if not code:
            return

        distance = WrcMainlineValidationRules._get_field_value(values, "distance")
        value_1st_dimension = WrcMainlineValidationRules._get_field_value(values, "value_1st_dimension")
        required_fields = []

        # All reference defects require distance and value_1st_dimension
        if distance is None:
            required_fields.append("distance")
        if value_1st_dimension is None:
            required_fields.append("value_1st_dimension")
        if required_fields:
            raise ValueError(f"{', '.join(required_fields)} is required for {code.full_name}")
