from datetime import date, time
from typing import Annotated, Optional, Union

from pydantic import Field

from ....records.wrc.cover_good_condition import CoverGoodCondition
from ....records.wrc.cover_shapes import CoverShape
from ....records.wrc.cover_types import CoverType
from ....records.wrc.flow_control_measures import FlowControlMeasure
from ....records.wrc.frame_good_condition import FrameGoodCondition
from ....records.wrc.inspection_methods import InspectionMethod
from ....records.wrc.inspection_purposes import InspectionPurpose
from ....records.wrc.inspection_stages import InspectionStage
from ....records.wrc.land_ownership_types import LandOwnershipType
from ....records.wrc.location_types import LocationTypeHighway, LocationTypeSewerage
from ....records.wrc.manhole_uses import ManholeUse
from ....records.wrc.materials import Material
from ....records.wrc.node_types import NodeType
from ....records.wrc.pre_cleaned_options import PreCleanedOptions
from ....records.wrc.shapes import Shape
from ....records.wrc.steps_materials import StepsMaterial
from ....records.wrc.temperature_options import Temperature
from ....records.wrc.type_of_steps import TypeOfSteps
from ....records.wrc.vertical_reference_points import VerticalReferencePoint
from ....records.wrc.video_image_formats import VideoImageFormat
from ....records.wrc.video_image_location_systems import VideoImageLocationSystem
from ....records.wrc.video_image_storage_media_options import VideoImageStorageMedia
from ....records.wrc.weather_options import WeatherOptions
from ....utils.xml_models import XMLModel


class Survey(XMLModel):
    client: Annotated[
        Optional[str], Field(default=None, description="Enter the name of the sewerage undertaker, highway authority, Highways Agency Region or other owner of the drain or sewer.")
    ]
    name_of_surveyor: Annotated[Optional[str], Field(default=None, description="Enter the name of the person responsible for completing the survey")]
    client_job_reference: Annotated[Optional[str], Field(default=None, description="Enter the client's job reference code")]
    contractor_job_reference: Annotated[Optional[str], Field(default=None, description="Enter the contractor's job reference code")]
    survey_date: Annotated[Optional[date], Field(default=None, description="Enter the survey date in the order day, month, year")]
    survey_time: Annotated[Optional[time], Field(default=None, description="Enter the time at the commencement of survey of drain/sewer length.")]
    pre_cleaned: Annotated[
        Optional[PreCleanedOptions],
        Field(default=None, description="State whether cleaning was carried out prior to the survey. Enter Y if pre-cleaning was carried out, N if it was not and Z if not known"),
    ]
    strategic_drain_sewer: Annotated[Optional[str], Field(default=None, description="Enter the sewer category code A, B or C as defined in the Sewer Risk Management website")]
    purpose_of_inspection: Annotated[Optional[Union[InspectionPurpose, str]], Field(default=None, description="Enter an appropriate code for the survey purpose")]
    inspection_stage: Annotated[Optional[InspectionStage], Field(default=None, description="Enter the code for inspection stage")]
    flow_control_measures: Annotated[Optional[FlowControlMeasure], Field(default=None, description="Enter the measures taken to deal with the flow at the time of the inspection")]
    weather: Annotated[Optional[WeatherOptions], Field(default=None, description="Enter an appropriate code for weather")]
    temperature: Annotated[Optional[Temperature], Field(default=None, description="Enter the temperature in Celsius or as a code")]
    method_of_inspection: Annotated[Optional[Union[InspectionMethod, str]], Field(default=None, description="Enter the codes for the method of inspection")]
    video_image_storage_media: Annotated[Optional[VideoImageStorageMedia], Field(default=None, description="Enter the type of media used for recording images")]
    video_image_location_system: Annotated[
        Optional[VideoImageLocationSystem], Field(default=None, description="For moving images, the method of recording the position on the video media should be recorded")
    ]
    video_image_format: Annotated[Optional[VideoImageFormat], Field(default=None, description="Enter the type of media used for storing videos")]
    video_image_file_name: Annotated[Optional[str], Field(default=None, description="Enter the name of the file as stored.")]
    video_volume_reference: Annotated[Optional[str], Field(default=None, description="Enter the reference number of the volume")]
    photograph_image_format: Annotated[Optional[str], Field(default=None, description="Enter the type of media used for storing images")]
    photograph_volume_reference: Annotated[Optional[str], Field(default=None, description="Enter the reference number of the film")]
    survey_type: Annotated[Optional[str], Field(default=None, description="Type of the survey")]  # Client defined field
    wrc_certified: Annotated[Optional[str], Field(default=None, description="Enter the WRC certified number.")]  # Client defined field
    requested_by: Annotated[Optional[str], Field(default=None, description="Enter the name of the person who requested the survey.")]  # Client defined field
    project_reference_number: Annotated[Optional[str], Field(default=None, description="Enter the project reference number.")]  # Client defined field
    sheet_number: Annotated[Optional[str], Field(default=None, description="Enter the sheet number.")]

    class Config:
        element_name_map = {
            "name_of_surveyor": "Surveyed_by",
            "survey_date": "Date",
            "survey_time": "Time",
            "pre_cleaned": "Pre_Cleaning",
            "strategic_drains_sewer": "Sewer_Category",
            "purpose_of_inspection": "Purpose_of_Survey",
            "client": "Customer",
            "client_job_reference": "Work_Order_Number",
            "contractor_job_reference": "PO_Number",
            "weather": "Weather",
            "flow_control_measures": "Flow_Control",
            "inspection_stage": "Inspection_Status",
            "method_of_inspection": "Inspection_Technology_Used",
            "survey_type": "Survey_Type",
            "video_image_file_name": "Media_Label",
        }
        ignore_fields = [
            "strategic_drain_sewer",
            "temperature",
            "video_image_storage_media",
            "video_image_location_system",
            "video_image_format",
            "video_volume_reference",
            "photograph_image_format",
            "photograph_volume_reference",
            "wrc_certified",
            "requested_by",
            "project_reference_number",
        ]


class Location(XMLModel):
    manhole_node_reference: Annotated[Optional[str], Field(default=None, description="Enter a reference in accordance with the manhole/node")]
    drainage_area: Annotated[Optional[str], Field(default=None, description="When provided by the client, this should be entered here.")]
    division_district: Annotated[Optional[str], Field(default=None, description="Enter an appropriate district/division code")]
    location_street_name: Annotated[Optional[str], Field(default=None, description="Enter “street name” through which the drain/sewer is situated.")]
    location_town_or_village: Annotated[Optional[str], Field(default=None, description="Enter a town, village or area where the drain/sewer is located.")]
    location_type_code: Annotated[
        Optional[LocationTypeSewerage | LocationTypeHighway], Field(default=None, description="Enter the appropriate code for the location of the drain/sewer.")
    ]
    location_details: Annotated[Optional[str], Field(default=None, description="Location Details of the access point or manhole")]  # Client defined field
    land_ownership: Annotated[Optional[LandOwnershipType], Field(default=None, description="This field is only to be used on the instruction of the client")]

    class Config:
        element_name_map = {
            "drainage_area": "Drainage_Area",
            "manhole_node_reference": "Pipe_Segment_Reference",
            "location_street_name": "Street",
            "location_town_or_village": "City",
            "location_type_code": "Location_Code",
            "location_details": "Location_Details",
        }
        ignore_fields = ["land_ownership"]

    @property
    def location_html(self) -> str:
        """
        HTML for location to be rendered into PDF
        """
        html = []
        if self.location_street_name:
            html.append(self.location_street_name)

        if self.location_town_or_village:
            html.append(self.location_town_or_village)

        if self.division_district:
            html.append(self.division_district)

        return "<br />".join(html)


class Manhole(XMLModel):
    node_type: Annotated[Optional[NodeType], Field(default=None, description="Enter the type of node")]
    vertical_reference_point: Annotated[Optional[VerticalReferencePoint], Field(default=None, description="Enter an appropriate vertical reference point code used in the survey")]
    circumferential_reference_point: Annotated[
        Optional[str], Field(default=None, description="The circumferential reference point is defined as being the lowest outgoing pipeline")
    ]
    use_of_manhole_inspection_chamber: Annotated[Optional[ManholeUse], Field(default=None, description="Enter codes to define the use of the manhole/inspection chamber")]
    type_of_cover: Annotated[Optional[CoverType], Field(default=None, description="The type of the cover plate")]  # Client defined field
    shape_of_cover: Annotated[Optional[CoverShape], Field(default=None, description="Enter codes to describe the manhole/inspection chamber cover shape")]
    material_of_cover: Annotated[Optional[Material], Field(default=None, description="Enter codes for the cover material.")]
    width_of_cover: Annotated[Optional[float], Field(default=None, description="Enter the width of the cover of the manhole/inspection chamber in millimetres")]
    breadth_of_cover: Annotated[Optional[float], Field(default=None, description="Enter the breadth of the cover of the manhole/inspection chamber in millimetres")]
    cover_level: Annotated[Optional[float], Field(default=None, description="Enter the level of the cover of the manhole/inspection chamber in metres.")]
    shape_of_access: Annotated[Optional[CoverShape], Field(default=None, description="Enter the shape of access to the manhole/inspection chamber")]
    width_of_access: Annotated[
        Optional[float], Field(default=None, description="Enter the width of the smallest part of the access into the manhole/inspection chamber in millimetres.")
    ]
    chamber_size: Annotated[Optional[float], Field(default=None, description="Enter the height of the chamber")]  # Client defined field
    breadth_of_access: Annotated[
        Optional[float], Field(default=None, description="Enter the breadth of the smallest part of the access into the manhole/inspection chamber in millimetres.")
    ]
    material: Annotated[Optional[Material], Field(default=None, description="Enter codes for manhole/inspection chamber material")]
    type_of_steps: Annotated[Optional[TypeOfSteps], Field(default=None, description="Enter the type of steps or ladder used in the manhole/inspection chamber:")]
    material_of_steps: Annotated[
        Optional[StepsMaterial], Field(default=None, description="Enter the code for the material of steps or ladder used in the manhole/inspection chamber:")
    ]
    chamber_unit_length: Annotated[Optional[float], Field(default=None, description="Enter the length in millimetres of the individual manhole/inspection chamber ring unit.")]
    standard: Annotated[Optional[str], Field(default="WRc 5.0", description="Enter the version of the standard used to record the data.")]
    year_constructed: Annotated[Optional[int], Field(default=None, description="Enter the actual year the drain/sewer was constructed")]
    cover_good_condition: Annotated[Optional[CoverGoodCondition], Field(default=None, description="Check if the cover is in good condition")]  # Client defined field
    frame_good_condition: Annotated[Optional[FrameGoodCondition], Field(default=None, description="Check if the frame is in good condition")]  # Client defined field
    water_level: Annotated[Optional[int], Field(default=None, description="Water level of the access")]  # Client defined field
    channel_level: Annotated[Optional[int], Field(default=None, description="Water level of the channel")]  # Client defined field
    chamber_shape: Annotated[Optional[Shape], Field(default=None, description="Shape of the Chamber")]  # Client defined field

    class Config:
        element_name_map = {
            "use_of_manhole_inspection_chamber": "Pipe_Use",
            "shape_of_access": "Shape",
            "material": "Material",
            "width_of_access": "Width",
            "year_constructed": "Year_Contstructed",
            "standard": "Manual_Version",
            "chamber_size": "Height",
        }
        ignore_fields = [
            "material_of_steps",
            "chamber_unit_length",
            "circumferential_reference_point",
            "type_of_cover",
            "shape_of_cover",
            "material_of_cover",
            "width_of_cover",
            "breadth_of_cover",
            "cover_level",
            "vertical_reference_point",
            "node_type",
            "breadth_of_access",
            "chamber_shape",
            "channel_level",
            "water_level",
            "frame_good_condition",
            "cover_good_condition",
        ]


class Measurements(XMLModel):
    manhole_node_coordinates: Annotated[Optional[str], Field(default=None, description="This consists of the Ordnance Survey map number and 100-meter grid coordinates")]
    ground_level: Annotated[Optional[float], Field(default=None, description="Coverplate Ground Level")]  # Client defined field
    invert_level: Annotated[Optional[float], Field(default=None, description="Coverplate Invert Level")]  # Client defined field
    cctv_depth: Annotated[Optional[float], Field(default=None, description="Indicates the depth from surface level to the point where the CCTV inspection was conducted.")]
    sip_depth: Annotated[Optional[float], Field(default=None, description="Indicates the depth from surface level to the end point.")]

    class Config:
        element_name_map = {
            "manhole_node_coordinates": "MH_Coordinate_System",
        }
        ignore_fields = ["cctv_depth", "sip_depth", "ground_level", "invert_level"]


class ManholeInspectionHeaders(XMLModel):
    survey: Annotated[Survey, Field(default_factory=Survey, description="Enter the survey details")]
    location: Annotated[Location, Field(default_factory=Location, description="Enter the location details")]
    manhole: Annotated[Manhole, Field(default_factory=Manhole, description="Enter the manhole details")]
    measurements: Annotated[Measurements, Field(default_factory=Measurements, description="Enter the measurements details")]
    general_remarks: Annotated[Optional[str], Field(default=None, description="Enter any general information relevant to the survey")]

    class Config:
        element_name_map = {
            "survey": "General",
            "location": "Location",
            "manhole": "Pipe",
            "measurements": "Measurements",
            "general_remarks": "Additional_Info",
        }
