import os
from pathlib import Path
from typing import Optional

from typing_extensions import Literal

from ...models.wrc.manhole.inspection import ManholeInspection
from ...records.wrc.inspection_methods import InspectionMethod
from ...records.wrc.inspection_purposes import InspectionPurpose
from ...utils.pdf_reports import generate_pdf


def _ensure_header_is_dict(inspection_dict: dict) -> None:
    """
    Ensure the header in inspection_dict is converted to a dictionary.
    For WRC Manhole headers we don't currently have a section_string property,
    but if one is added in the future we preserve it.
    """
    if "header" in inspection_dict and hasattr(inspection_dict["header"], "__dict__"):
        header_obj = inspection_dict["header"]
        header_dict = header_obj.__dict__.copy()
        # Preserve section_string only if it exists on the header object
        if hasattr(header_obj, "section_string"):
            header_dict["section_string"] = header_obj.section_string
        inspection_dict["header"] = header_dict


def generate_wrc_manhole_pdf(
    inspection: ManholeInspection,
    annotated_frames_dir: str,
    pdf_output_path: str,
    video_name: str,
    uom: Literal["metric", "imperial"],
    logo_path: Optional[str] = None,
    address: Optional[str] = None,
    pdf_title: Optional[str] = None,
):
    """
    Generate a PDF report for the WRC Manhole.

    Args:
        inspection: The WRC Manhole inspection to generate a PDF report for.
        annotated_frames_dir: The path of the directory to the annotated frames.
        pdf_output_path: The path to the output PDF file.
        video_name: The name of the video.
        uom: The unit of measurement.
        logo_path: The path to the logo image.
        address: The address for the report.
        pdf_title: The title for the PDF report.
    Returns:
        The path to the generated PDF file.
    """

    inspection_dict = inspection.__dict__.copy()
    inspection_dict["observations"].sort(key=lambda x: x.distance)

    # Convert nested objects to dictionaries for easier manipulation
    _ensure_header_is_dict(inspection_dict)

    if "survey" in inspection_dict.get("header", {}) and hasattr(inspection_dict["header"]["survey"], "__dict__"):
        inspection_dict["header"]["survey"] = inspection_dict["header"]["survey"].__dict__.copy()

    # Process purpose_of_inspection, method_of_inspection - use label for enums, string as-is
    if hasattr(inspection.header.survey, "purpose_of_inspection") and inspection.header.survey.purpose_of_inspection:
        try:
            purpose_of_inspection = InspectionPurpose.from_abbreviation(inspection.header.survey.purpose_of_inspection).label
        except ValueError:
            purpose_of_inspection = inspection.header.survey.purpose_of_inspection
        inspection_dict["header"]["survey"]["purpose_of_inspection"] = purpose_of_inspection

    if hasattr(inspection.header.survey, "method_of_inspection") and inspection.header.survey.method_of_inspection:
        try:
            method_of_inspection = InspectionMethod.from_abbreviation(inspection.header.survey.method_of_inspection).label
        except ValueError:
            method_of_inspection = inspection.header.survey.method_of_inspection
        inspection_dict["header"]["survey"]["method_of_inspection"] = method_of_inspection

    # Enrich inspection with annotated frame URIs
    for index, observation in enumerate(inspection.observations):
        observation_dict = observation.__dict__.copy()
        annotated_frame_path = os.path.join(annotated_frames_dir, observation.image_reference)
        if not os.path.exists(annotated_frame_path):
            raise FileNotFoundError(f"Annotated frame file not found: {annotated_frame_path}")

        observation_dict["annotated_frame"] = Path(annotated_frame_path).absolute().as_uri()
        inspection_dict["observations"][index] = observation_dict

    measurement_units = "m" if uom == "metric" else "ft"

    image_prefix = ""
    if inspection.header.location.manhole_node_reference:
        image_prefix = f"{inspection.header.location.manhole_node_reference}-"
    if inspection.header.survey.survey_date:
        image_prefix = f"{image_prefix}{inspection.header.survey.survey_date.strftime('%d%m%y')}-"

    data = {
        "title": pdf_title or "WRC Manhole Report",
        "inspection": inspection_dict,
        "logo_path": logo_path,
        "video_name": video_name,
        "measurement_units": measurement_units,
        "address": address,
        "image_prefix": image_prefix,
    }

    pdf_path = generate_pdf("wrc/manhole/report.html", data, pdf_output_path)
    return pdf_path
