from typing import Annotated, Any, Dict, Optional

from pydantic import Field

from ....annotations.bounding_box import BoundingBox
from ....annotations.frame_size import FrameSize
from ....defects.wrc import WrcDefects
from ....records.wrc.components import Component
from ....records.wrc.materials import Material
from ....records.wrc.wrc_defects import WrcDefectRecords
from ....utils.defect_properties import DefectType
from ....utils.xml_models import XMLModel


class ManholeObservation(XMLModel):
    video_ref: Annotated[
        Optional[str],
        Field(default=None, description="The time reference to the location of entry on the video recording."),
    ]
    image_reference: Annotated[
        Optional[str],
        Field(default=None, description="Wherever a still image or photograph is taken of the feature, a reference should be given."),
    ]
    distance: Annotated[
        Optional[float],
        Field(default=None, description="Defect/observation observed on the number displayed on the distance counter."),
    ]
    continuous_defect: Annotated[
        Optional[str],
        Field(default=None, description="This is used to indicate the start, change or finish of a continuous code by use of the letters S, C or F."),
    ]
    component: Annotated[
        Optional[Component],
        Field(default=None, description="The Manhole Component Defect Section only records defects for the chimney, cone, wall, bench and channel."),
    ]
    code: Annotated[
        Optional[WrcDefectRecords],
        Field(default=None, description="The defect/observation code are entered."),
    ]
    joint: Annotated[
        Optional[str],
        Field(
            default=None,
            description=(
                "The letter 'J' should be added to the appropriate defect code where the defect starts and ends within 0.2m of a single pipe joint "
                "or if the defect is at or on the joint."
            ),
        ),
    ]
    material: Annotated[
        Optional[Material],
        Field(default=None, description="Where the codes 'MC' or 'LC' are used, the code for the new material or lining material needs to be entered."),
    ]
    band: Annotated[
        Optional[str],
        Field(
            default=None,
            description="The descriptions of certain codes allow the feature to be quantified based on certain bands, e.g Medium (M) or Large (L)",
        ),
    ]
    severity: Annotated[
        Optional[int],
        Field(default=None, description="Grade or Severity associated with the respective defect/observation."),
    ]
    value_1st_dimension: Annotated[
        Optional[str],
        Field(default=None, description="Physical measurements or manhole/node reference information are entered."),
    ]
    value_2nd_dimension: Annotated[
        Optional[str],
        Field(default=None, description="Physical measurements or manhole/node reference information are entered."),
    ]
    value_defect_percent: Annotated[
        Optional[int],
        Field(default=None, description="Where a code requires a percentage value."),
    ]
    circumferential_location_from: Annotated[
        Optional[int],
        Field(default=None, description="The defect/observation covers a range of clock positions that are entered."),
    ]
    circumferential_location_to: Annotated[
        Optional[int],
        Field(default=None, description="Defect clock position is entered. The defect/observation covers a range of clock position that are entered."),
    ]
    remarks: Annotated[
        Optional[str],
        Field(default=None, description="Enter appropriate details about the defect/observation."),
    ]
    bounding_box: Annotated[Optional[BoundingBox], Field(default=None, description="Bounding box of the defect")]
    size: Annotated[Optional[FrameSize], Field(default=None, description="Annotated frame of the defect")]

    # Capture Pipe connection for selected defect codes and validate
    shape_of_pipe_connection: Annotated[Optional[str], Field(default=None, description="Shape of pipe connection")]
    diameter_of_pipe_connection: Annotated[Optional[float], Field(default=None, description="Diameter of pipe connection")]
    width_of_pipe_connection: Annotated[Optional[float], Field(default=None, description="Width of pipe connection")]

    def get_extra_fields(self) -> Dict[str, Any]:
        defect_type = WrcDefects.get_defect_type(self.code)
        extra_fields = {
            "filename": self.image_reference,
            "object": {
                "name": self.code.full_name,
                "bndbox": self.bounding_box,
                "continuous_defect": self.continuous_defect,
                "distance": self.distance,
                "image_distance": None,
                "first_dimension": self.value_1st_dimension,
                "second_dimension": self.value_2nd_dimension,
                "defect_percentage": self.value_defect_percent,
                "severity": self.severity,
                "joint": self.joint,
                "from": self.circumferential_location_from,
                "to": self.circumferential_location_to,
                "video_ref": self.video_ref,
                "remarks": self.remarks,
                "is_structural": 1 if defect_type == DefectType.structural else 0,
                "is_om": 1 if defect_type == DefectType.operational_and_maintenance else 0,
            },
        }
        return extra_fields

    class Config:
        ignore_fields = [
            "image_reference",
            "code",
            "bounding_box",
            "continuous_defect",
            "distance",
            "image_distance",
            "value_1st_dimension",
            "value_2nd_dimension",
            "value_defect_percent",
            "severity",
            "joint",
            "circumferential_location_from",
            "circumferential_location_to",
            "video_ref",
            "remarks",
            "is_structural",
            "is_om",
            "component",
            "step",
            "shape_of_pipe_connection",
            "diameter_of_pipe_connection",
            "width_of_pipe_connection",
            "material",
            "band",
        ]
