"""Module template was autogenerated from sharepoint list schema."""

import re
from dataclasses import dataclass
from datetime import date, datetime
from decimal import Decimal, DecimalException
from enum import Enum
from typing import Any, List, Optional

from aind_data_schema.core.procedures import (
    IntraperitonealInjection,
    NonViralMaterial,
    RetroOrbitalInjection,
    Side,
    Surgery,
    ViralMaterial,
)

from aind_metadata_service.sharepoint.las2020.models import (
    Doseroute,
    LASList,
    Rosop,
)


class IacucProtocol(Enum):
    """Enum class for Iacuc Protocols."""

    N_2103 = "2103"
    N_2104 = "2104"
    N_2105 = "2105"
    N_2106 = "2106"
    N_2107 = "2107"
    N_2109 = "2109"
    N_2110 = "2110"
    N_2112 = "2112"
    N_2113 = "2113"
    N_2114 = "2114"
    N_2115 = "2115"
    N_2116 = "2116"
    N_2117 = "2117"
    N_2118 = "2118"
    N_2119 = "2119"
    N_2120 = "2120"
    N_2201 = "2201"
    N_2202 = "2202"
    N_2204 = "2204"
    N_2205 = "2205"
    N_2207 = "2207"
    N_2212 = "2212"
    N_2301 = "2301"
    N_2304 = "2304"
    N_2305 = "2305"
    N_2306 = "2306"
    N_2307 = "2307"
    N_2308 = "2308"
    N_2401 = "2401"
    N_2402 = "2402"
    N_2405 = "2405"
    N_2406 = "2406"
    N_2412 = "2412"


@dataclass
class RequestedProcedureInfo:
    """Container for requested procedure information"""

    procedure: Optional[str] = None
    preferred_age: Optional[Decimal] = None
    preferred_date: Optional[date] = None


@dataclass
class InjectableMaterial:
    """Container for injectable material information"""

    substance: Optional[str] = None
    prep_lot_id: Optional[str] = None
    genome_copy: Optional[str] = None
    virus_volume: Optional[Decimal] = None
    titer: Optional[str] = None


@dataclass
class RetroOrbitalInjectionInfo:
    """Container for ro injection information"""

    # TODO: support "either for eye"
    ro_sop: Optional[Rosop] = None
    animal_id: Optional[str] = None
    injection_eye: Optional[Side] = None
    injection_volume: Optional[Decimal] = None
    tube_label: Optional[str] = None
    box_label: Optional[str] = None
    injectable_materials: Optional[List[InjectableMaterial]] = None


class LASProcedure(Enum):
    """Enum class of requested procedure types"""

    BLOOD_COLLECTION = "Blood Collection"
    CEREBROSPINAL_FLUID = "Cerebrospinal Fluid Collection (CSF)"
    DOSING = "Dosing"
    INDUCTION = "Induction"
    IC_INJECTION = "Intracerebroventricular Injection"
    OTHER = "Other"
    RETRO_ORBITAL_INJECTION = "Retro-Orbital Injection"
    TISSUE_COLLECTION = "Tissue Collection"


class MappedLASList:
    """Mapped Fields in Sharepoint list"""

    STANDARD_DOSE_REGEX = re.compile(
        r"^([a-zA-Z0-9\s\-\(\)]+?)\s+(\d+(\.\d+)?)?\s*([a-zA-Z%\/]+)?"
    )
    DOSE_PAREN_REGEX = re.compile(r"\((\d+(\.\d+)?)\s*([a-zA-Z%\/]+)\)")
    SCIENTIFIC_NOTATION_REGEX = re.compile(r"^[-+]?\d+(?:\.\d+)?[eE][-+]?\d+$")
    VALUE_WITH_UNIT_REGEX = re.compile(r"^([\d\.eE+-]+)\s*(\S+)$")
    INTEGER_REGEX = re.compile(r"^[+-]?\d+$")

    def __init__(self, las: LASList):
        """Class constructor"""
        self._las = las

    @staticmethod
    def _parse_basic_decimal_str(value: Optional[str]) -> Optional[Decimal]:
        """Parse string representation of decimal such as '0.25'."""
        try:
            return None if value is None else Decimal(value)
        except (ValueError, DecimalException):
            return None

    @staticmethod
    def _parse_datetime_to_date(dt: Optional[datetime]) -> Optional[date]:
        """Parse date from datetime"""
        return None if dt is None else dt.date()

    def _parse_dose_sub_to_nonviral_material(
        self, dose_sub: Optional[str]
    ) -> Optional[NonViralMaterial]:
        """
        Parses substance name, concentration, and concentration unit from dose
        if it follows a common pattern into aind NonViralMaterial model.
        """
        # if string is long it probably contains too much information
        if (dose_sub and len(dose_sub) > 30) or dose_sub is None:
            return None

        match = re.match(self.STANDARD_DOSE_REGEX, dose_sub.strip())
        if match:
            material = match.group(1).strip().lower().capitalize()
            concentration_value = match.group(2) if match.group(2) else None
            concentration_unit = (
                match.group(4).lower() if match.group(4) else None
            )

            # If no concentration found, look in parentheses
            if not concentration_value or not concentration_unit:
                parens_match = re.search(self.DOSE_PAREN_REGEX, dose_sub)
                if parens_match:
                    concentration_value = parens_match.group(1)
                    concentration_unit = parens_match.group(3).lower()

            return NonViralMaterial.model_construct(
                name=material,
                concentration=self._parse_basic_decimal_str(
                    concentration_value
                ),
                concentration_unit=concentration_unit,
            )
        else:
            # If it doesn't match pattern, return full string in name
            return NonViralMaterial.model_construct(
                name=dose_sub,
            )

    def _is_scientific_notation(self, value_str: str) -> bool:
        """Checks whether titer field is in scientific notation."""
        return bool(re.search(self.SCIENTIFIC_NOTATION_REGEX, value_str))

    def _is_value_with_unit(self, value_str: str) -> bool:
        """Checks whether titer field is in titer with unit format."""
        return bool(re.search(self.VALUE_WITH_UNIT_REGEX, value_str))

    def _parse_titer_str(self, titer_str: str) -> Optional[float]:
        """Parse string representation of titer into float."""
        if re.match(self.INTEGER_REGEX, titer_str):
            return int(float(titer_str))
        return None

    def _parse_titer(self, titer_str: Optional[str]) -> Optional[tuple]:
        """Parses titer field to integer."""
        unit = "gc/mL"  # default unit
        if titer_str is None:
            return None, unit

        titer_str = titer_str.strip()
        numeric_value = self._parse_titer_str(titer_str)
        if numeric_value is not None:
            return numeric_value, unit

        titer_str = titer_str.strip()
        # If the string matches scientific notation
        if self._is_scientific_notation(titer_str):
            titer = float(
                re.match(self.SCIENTIFIC_NOTATION_REGEX, titer_str).group(0)
            )
            return int(titer), unit  # Always return an integer

        # Check if the string has a value with unit
        elif self._is_value_with_unit(titer_str):
            match = re.match(self.VALUE_WITH_UNIT_REGEX, titer_str)
            titer = match.group(1)
            unit = match.group(2)
            # Convert only the numeric value part
            numeric_value = self._parse_titer_str(titer)
            if numeric_value is not None:
                return numeric_value, unit

        # If none of the above, return None with default unit
        return None, unit

    @property
    def aind_accommodation_comment(self) -> Optional[str]:
        """Maps accommodation_comment to aind model"""
        return self._las.accommodation_comment

    @property
    def aind_acsf_time1(self) -> Optional[str]:
        """Maps acsf_time1 to aind model"""
        return self._las.acsf_time1

    @property
    def aind_acsf_time2(self) -> Optional[str]:
        """Maps acsf_time2 to aind model"""
        return self._las.acsf_time2

    @property
    def aind_acsf_time3(self) -> Optional[str]:
        """Maps acsf_time3 to aind model"""
        return self._las.acsf_time3

    @property
    def aind_acsf_time4(self) -> Optional[str]:
        """Maps acsf_time4 to aind model"""
        return self._las.acsf_time4

    @property
    def aind_acsf_time5(self) -> Optional[str]:
        """Maps acsf_time5 to aind model"""
        return self._las.acsf_time5

    @property
    def aind_acsfid1(self) -> Optional[str]:
        """Maps acsfid1 to aind model"""
        return self._las.acsfid1

    @property
    def aind_acsfid2(self) -> Optional[str]:
        """Maps acsfid2 to aind model"""
        return self._las.acsfid2

    @property
    def aind_acsfid3(self) -> Optional[str]:
        """Maps acsfid3 to aind model"""
        return self._las.acsfid3

    @property
    def aind_acsfid4(self) -> Optional[str]:
        """Maps acsfid4 to aind model"""
        return self._las.acsfid4

    @property
    def aind_acsfid5(self) -> Optional[str]:
        """Maps acsfid5 to aind model"""
        return self._las.acsfid5

    @property
    def aind_afternoon_pf(self) -> Optional[bool]:
        """Maps afternoon_pf to aind model"""
        return self._las.afternoon_pf

    @property
    def aind_author_id(self) -> Optional[str]:
        """Maps author_id to aind model"""
        return (
            None
            if self._las.author_id is None
            else f"LAS-{str(self._las.author_id)}"
        )

    @property
    def aind_author_lookup_id(self) -> Optional[str]:
        """Maps author_lookup_id to aind model"""
        return (
            None
            if self._las.author_lookup_id is None
            else f"LAS-{str(self._las.author_lookup_id)}"
        )

    @property
    def aind_bc_age(self) -> Optional[str]:
        """Maps bc_age to aind model"""
        return self._las.bc_age

    @property
    def aind_bc_genotypes(self) -> Optional[str]:
        """Maps bc_genotypes to aind model"""
        return self._las.bc_genotypes

    @property
    def aind_bc_location(self) -> Optional[str]:
        """Maps bc_location to aind model"""
        return self._las.bc_location

    @property
    def aind_bc_tube(self) -> Optional[str]:
        """Maps bc_tube to aind model"""
        return self._las.bc_tube

    @property
    def aind_bc_type(self) -> Optional[Any]:
        """Maps bc_type to aind model"""
        return (
            None
            if self._las.bc_type is None
            else {
                self._las.bc_type.SUBMANDIBULAR_IMMUNOLOGY: None,
                self._las.bc_type.SUBMANDIBULAR: None,
                self._las.bc_type.TERMINAL: None,
            }.get(self._las.bc_type, None)
        )

    @property
    def aind_bc_volume(self) -> Optional[str]:
        """Maps bc_volume to aind model"""
        return self._las.bc_volume

    @property
    def aind_color_tag(self) -> Optional[str]:
        """Maps color_tag to aind model"""
        return self._las.color_tag

    @property
    def aind_compliance_asset_id(self) -> Optional[str]:
        """Maps compliance_asset_id to aind model"""
        return self._las.compliance_asset_id

    @property
    def aind_created(self) -> Optional[datetime]:
        """Maps created to aind model"""
        return self._las.created

    @property
    def aind_custcontact(self) -> Optional[str]:
        """Maps custcontact to aind model"""
        return self._las.custcontact

    @property
    def aind_custom_com1(self) -> Optional[str]:
        """Maps custom_com1 to aind model"""
        return self._las.custom_com1

    @property
    def aind_custom_com2(self) -> Optional[str]:
        """Maps custom_com2 to aind model"""
        return self._las.custom_com2

    @property
    def aind_custpresent(self) -> Optional[bool]:
        """Maps custpresent to aind model"""
        return self._las.custpresent

    @property
    def aind_dose_route(self) -> Optional[Doseroute]:
        """Maps dose_route to aind model"""
        return self._las.dose_route

    @property
    def aind_dose_sub(self) -> Optional[NonViralMaterial]:
        """Maps dose_sub to aind model"""
        return self._parse_dose_sub_to_nonviral_material(self._las.dose_sub)

    @property
    def aind_dose_where(self) -> Optional[str]:
        """Maps dose_where to aind model"""
        return self._las.dose_where

    @property
    def aind_doseduration(self) -> Optional[Decimal]:
        """Maps doseduration to aind model"""
        return self._parse_basic_decimal_str(self._las.doseduration)

    @property
    def aind_dosevolume(self) -> Optional[Decimal]:
        """Maps dosevolume to aind model"""
        return self._parse_basic_decimal_str(self._las.dosevolume)

    @property
    def aind_doxycycline(self) -> Optional[bool]:
        """Maps doxycycline to aind model"""
        return self._las.doxycycline

    @property
    def aind_editor_id(self) -> Optional[int]:
        """Maps editor_id to aind model"""
        return self._las.editor_id

    @property
    def aind_icv_comment(self) -> Optional[str]:
        """Maps icv_comment to aind model"""
        return self._las.icv_comment

    @property
    def aind_icv_id1(self) -> Optional[str]:
        """Maps icv_id1 to aind model"""
        return self._las.icv_id1

    @property
    def aind_icv_id2(self) -> Optional[str]:
        """Maps icv_id2 to aind model"""
        return self._las.icv_id2

    @property
    def aind_icv_id3(self) -> Optional[str]:
        """Maps icv_id3 to aind model"""
        return self._las.icv_id3

    @property
    def aind_icv_id4(self) -> Optional[str]:
        """Maps icv_id4 to aind model"""
        return self._las.icv_id4

    @property
    def aind_icv_id5(self) -> Optional[str]:
        """Maps icv_id5 to aind model"""
        return self._las.icv_id5

    @property
    def aind_icv_lims(self) -> Optional[Any]:
        """Maps icv_lims to aind model"""
        return (
            None
            if self._las.icv_lims is None
            else {
                self._las.icv_lims.STEREOTAXIC_INJECTIONS: None,
                self._las.icv_lims.NEW_STEREOTAXIC_INJECTION: None,
            }.get(self._las.icv_lims, None)
        )

    @property
    def aind_icv_route1(self) -> Optional[Any]:
        """Maps icv_route1 to aind model"""
        return (
            None
            if self._las.icv_route1 is None
            else {
                self._las.icv_route1.BILATERAL: None,
                self._las.icv_route1.ANY_UNILATERAL: None,
                self._las.icv_route1.LEFT_UNILATERAL: None,
                self._las.icv_route1.RIGHT_UNILATERAL: None,
            }.get(self._las.icv_route1, None)
        )

    @property
    def aind_icv_route2(self) -> Optional[Any]:
        """Maps icv_route2 to aind model"""
        return (
            None
            if self._las.icv_route2 is None
            else {
                self._las.icv_route2.BILATERAL: None,
                self._las.icv_route2.ANY_UNILATERAL: None,
                self._las.icv_route2.LEFT_UNILATERAL: None,
                self._las.icv_route2.RIGHT_UNILATERAL: None,
            }.get(self._las.icv_route2, None)
        )

    @property
    def aind_icv_route3(self) -> Optional[Any]:
        """Maps icv_route3 to aind model"""
        return (
            None
            if self._las.icv_route3 is None
            else {
                self._las.icv_route3.BILATERAL: None,
                self._las.icv_route3.ANY_UNILATERAL: None,
                self._las.icv_route3.LEFT_UNILATERAL: None,
                self._las.icv_route3.RIGHT_UNILATERAL: None,
            }.get(self._las.icv_route3, None)
        )

    @property
    def aind_icv_route4(self) -> Optional[Any]:
        """Maps icv_route4 to aind model"""
        return (
            None
            if self._las.icv_route4 is None
            else {
                self._las.icv_route4.BILATERAL: None,
                self._las.icv_route4.ANY_UNILATERAL: None,
                self._las.icv_route4.LEFT_UNILATERAL: None,
                self._las.icv_route4.RIGHT_UNILATERAL: None,
            }.get(self._las.icv_route4, None)
        )

    @property
    def aind_icv_route5(self) -> Optional[Any]:
        """Maps icv_route5 to aind model"""
        return (
            None
            if self._las.icv_route5 is None
            else {
                self._las.icv_route5.BILATERAL: None,
                self._las.icv_route5.ANY_UNILATERAL: None,
                self._las.icv_route5.LEFT_UNILATERAL: None,
                self._las.icv_route5.RIGHT_UNILATERAL: None,
            }.get(self._las.icv_route5, None)
        )

    @property
    def aind_icv_sub1(self) -> Optional[str]:
        """Maps icv_sub1 to aind model"""
        return self._las.icv_sub1

    @property
    def aind_icv_sub2(self) -> Optional[str]:
        """Maps icv_sub2 to aind model"""
        return self._las.icv_sub2

    @property
    def aind_icv_sub3(self) -> Optional[str]:
        """Maps icv_sub3 to aind model"""
        return self._las.icv_sub3

    @property
    def aind_icv_sub4(self) -> Optional[str]:
        """Maps icv_sub4 to aind model"""
        return self._las.icv_sub4

    @property
    def aind_icv_sub5(self) -> Optional[str]:
        """Maps icv_sub5 to aind model"""
        return self._las.icv_sub5

    @property
    def aind_id(self) -> Optional[int]:
        """Maps id to aind model"""
        return self._las.id

    @property
    def aind_l_ta_id1(self) -> Optional[str]:
        """Maps l_ta_id1 to aind model"""
        return self._las.l_ta_id1

    @property
    def aind_l_ta_id2(self) -> Optional[str]:
        """Maps l_ta_id2 to aind model"""
        return self._las.l_ta_id2

    @property
    def aind_l_ta_id3(self) -> Optional[str]:
        """Maps l_ta_id3 to aind model"""
        return self._las.l_ta_id3

    @property
    def aind_l_ta_id4(self) -> Optional[str]:
        """Maps l_ta_id4 to aind model"""
        return self._las.l_ta_id4

    @property
    def aind_l_ta_id5(self) -> Optional[str]:
        """Maps l_ta_id5 to aind model"""
        return self._las.l_ta_id5

    @property
    def aind_l_tdate1(self) -> Optional[datetime]:
        """Maps l_tdate1 to aind model"""
        return self._las.l_tdate1

    @property
    def aind_l_tdate2(self) -> Optional[datetime]:
        """Maps l_tdate2 to aind model"""
        return self._las.l_tdate2

    @property
    def aind_l_tdate3(self) -> Optional[datetime]:
        """Maps l_tdate3 to aind model"""
        return self._las.l_tdate3

    @property
    def aind_l_tdate4(self) -> Optional[datetime]:
        """Maps l_tdate4 to aind model"""
        return self._las.l_tdate4

    @property
    def aind_l_tdate5(self) -> Optional[datetime]:
        """Maps l_tdate5 to aind model"""
        return self._las.l_tdate5

    @property
    def aind_las_comments(self) -> Optional[str]:
        """Maps las_comments to aind model"""
        return self._las.las_comments

    @property
    def aind_lims_entry(self) -> Optional[bool]:
        """Maps lims_entry to aind model"""
        return self._las.lims_entry

    @property
    def aind_lims_project(self) -> Optional[Any]:
        """Maps lims_project to aind model"""
        return (
            None
            if self._las.lims_project is None
            else {
                self._las.lims_project.N_0200: None,
                self._las.lims_project.N_0309: None,
                self._las.lims_project.N_0310: None,
                self._las.lims_project.N_0311: None,
                self._las.lims_project.N_0312: None,
                self._las.lims_project.N_0314: None,
                self._las.lims_project.N_0316: None,
                self._las.lims_project.N_0319: None,
                self._las.lims_project.N_0320: None,
                self._las.lims_project.N_0321: None,
                self._las.lims_project.N_03212: None,
                self._las.lims_project.N_03213: None,
                self._las.lims_project.N_03214: None,
                self._las.lims_project.N_0322: None,
                self._las.lims_project.N_0324: None,
                self._las.lims_project.N_0325: None,
                self._las.lims_project.N_0326: None,
                self._las.lims_project.N_0327: None,
                self._las.lims_project.N_03272: None,
                self._las.lims_project.N_0328: None,
                self._las.lims_project.N_0329: None,
                self._las.lims_project.N_0331: None,
                self._las.lims_project.N_0334: None,
                self._las.lims_project.N_03342: None,
                self._las.lims_project.N_0335: None,
                self._las.lims_project.N_0336: None,
                self._las.lims_project.N_0338: None,
                self._las.lims_project.N_0339: None,
                self._las.lims_project.N_03392: None,
                self._las.lims_project.N_0340: None,
                self._las.lims_project.N_0342: None,
                self._las.lims_project.N_03422: None,
                self._las.lims_project.N_0343: None,
                self._las.lims_project.N_0344: None,
                self._las.lims_project.N_0345: None,
                self._las.lims_project.N_0346: None,
                self._las.lims_project.N_0350: None,
                self._las.lims_project.N_0350X: None,
                self._las.lims_project.N_0351: None,
                self._las.lims_project.N_0351X: None,
                self._las.lims_project.N_0354: None,
                self._las.lims_project.N_0355: None,
                self._las.lims_project.N_0357: None,
                self._las.lims_project.N_0358: None,
                self._las.lims_project.N_0359: None,
                self._las.lims_project.N_0360: None,
                self._las.lims_project.N_03602: None,
                self._las.lims_project.N_0362: None,
                self._las.lims_project.N_0363: None,
                self._las.lims_project.N_0364: None,
                self._las.lims_project.N_0365: None,
                self._las.lims_project.N_0365X: None,
                self._las.lims_project.N_0366: None,
                self._las.lims_project.N_0366X: None,
                self._las.lims_project.N_0367: None,
                self._las.lims_project.N_0369: None,
                self._las.lims_project.N_0371: None,
                self._las.lims_project.N_0372: None,
                self._las.lims_project.N_0372X: None,
                self._las.lims_project.N_0374: None,
                self._las.lims_project.N_0376: None,
                self._las.lims_project.N_0376A: None,
                self._las.lims_project.N_0376X: None,
                self._las.lims_project.N_0378: None,
                self._las.lims_project.N_0378X: None,
                self._las.lims_project.N_0380: None,
                self._las.lims_project.N_0384: None,
                self._las.lims_project.N_0386: None,
                self._las.lims_project.N_0388: None,
                self._las.lims_project.AINDMSMA: None,
                self._las.lims_project.AINDDISCOVERY: None,
                self._las.lims_project.AINDEPHYS: None,
                self._las.lims_project.AINDOPHYS: None,
                self._las.lims_project.APR_OX: None,
                self._las.lims_project.A_XL_OX: None,
                self._las.lims_project.BA_RSEQ_GENETIC_TOOLS: None,
                self._las.lims_project.BRAIN_STIM: None,
                self._las.lims_project.BRAINTV_VIRAL_STRATEGIES: None,
                self._las.lims_project.C200: None,
                self._las.lims_project.C600: None,
                self._las.lims_project.C600_LATERAL: None,
                self._las.lims_project.C600X: None,
                self._las.lims_project.CELLTYPES_TRANSGENIC_CHAR: None,
                self._las.lims_project.CITRICACIDPILOT: None,
                self._las.lims_project.CON9999: None,
                self._las.lims_project.CONC505: None,
                self._las.lims_project.CONCS04: None,
                self._las.lims_project.DEEPSCOPE_SLM_DEVELOPMENT: None,
                self._las.lims_project.DYNAMIC_ROUTING_BEHAVIOR: None,
                self._las.lims_project.DYNAMIC_ROUTING_OPTO_DEV: None,
                self._las.lims_project.DYNAMIC_ROUTING_SURGICAL: None,
                self._las.lims_project.DYNAMIC_ROUTING_TASK1_PRO: None,
                self._las.lims_project.DYNAMIC_ROUTING_TASK2_PRO: None,
                self._las.lims_project.DYNAMIC_ROUTING_ULTRA_OPT: None,
                self._las.lims_project.H120: None,
                self._las.lims_project.H200: None,
                self._las.lims_project.H301: None,
                self._las.lims_project.H301T: None,
                self._las.lims_project.H301_X: None,
                self._las.lims_project.H501_X: None,
                self._las.lims_project.H504: None,
                self._las.lims_project.IS_IX: None,
                self._las.lims_project.LARGE_SCALE_VOLTAGE: None,
                self._las.lims_project.LEARNINGM_FISH_DEVELOPMEN: None,
                self._las.lims_project.LEARNINGM_FISH_TASK1_A: None,
                self._las.lims_project.M301T: None,
                self._las.lims_project.MESOSCOPE_DEVELOPMENT: None,
                self._las.lims_project.M_FISH_PLATFORM_DEVELOPME: None,
                self._las.lims_project.MINDSCOPE_TRANSGENIC_CHAR: None,
                self._las.lims_project.M_IVSCCMET: None,
                self._las.lims_project.M_IVSCCME_TX: None,
                self._las.lims_project.M_M_PATCHX: None,
                self._las.lims_project.M_MPATC_HX: None,
                self._las.lims_project.MOUSE_BRAIN_CELL_ATLAS_CH: None,
                self._las.lims_project.MOUSE_BRAIN_CELL_ATLA_001: None,
                self._las.lims_project.MOUSE_BRAIN_CELL_ATLAS_TR: None,
                self._las.lims_project.MOUSE_FULL_MORPHOLOGY_FMO: None,
                self._las.lims_project.MOUSE_GENETIC_TOOLS_PROJE: None,
                self._las.lims_project.M_VISPTAXLO: None,
                self._las.lims_project.MULTISCOPE_SIGNAL_NOISE: None,
                self._las.lims_project.N200: None,
                self._las.lims_project.N310: None,
                self._las.lims_project.NEUROPIXEL_VISUAL_BEHAVIO: None,
                self._las.lims_project.NEUROPIXEL_VISUAL_BEH_001: None,
                self._las.lims_project.NEUROPIXEL_VISUAL_CODING: None,
                self._las.lims_project.OLVSX: None,
                self._las.lims_project.OM_FIS_HCOREGISTRATIONPIL: None,
                self._las.lims_project.OM_FISH_CUX2_MESO: None,
                self._las.lims_project.OM_FISH_GAD2_MESO: None,
                self._las.lims_project.OM_FISH_GAD2_PILOT: None,
                self._las.lims_project.OM_FISH_RBP4_MESO: None,
                self._las.lims_project.OM_FISH_RORB_PILOT: None,
                self._las.lims_project.OM_FISHRO_BINJECTIONVIRUS: None,
                self._las.lims_project.OM_FISH_SST_MESO: None,
                self._las.lims_project.OM_FISH_VIP_MESO: None,
                self._las.lims_project.OPEN_SCOPE_DENDRITE_COUPL: None,
                self._las.lims_project.OPENSCOPE_DEVELOPMENT: None,
                self._las.lims_project.OPEN_SCOPE_ILLUSION: None,
                self._las.lims_project.OPEN_SCOPE_GLOBAL_LOCAL_O: None,
                self._las.lims_project.OPENSCOPE_GAMMA_PILOT: None,
                self._las.lims_project.OPENSCOPE_GAMMA_PRODUCTLO: None,
                self._las.lims_project.OPENSCOPELNJECTION_PILOT: None,
                self._las.lims_project.OPEN_SCOPE_LOOP: None,
                self._las.lims_project.OPENSCOPE_MOTION_PLLOT: None,
                self._las.lims_project.OPENSCOPE_MOTION_PRODUCTI: None,
                self._las.lims_project.OPENSCOPE_MULTIPLEX_PILOT: None,
                self._las.lims_project.OPENSCOPE_MULTIPLEX_PRODU: None,
                self._las.lims_project.OPEN_SCOPE_PSYCODE: None,
                self._las.lims_project.OPEN_SCOPE_SEQUENCE_LEARN: None,
                self._las.lims_project.OPEN_SCOPE_TEMPORAL_BARCO: None,
                self._las.lims_project.OPEN_SCOPE_TEXTURE: None,
                self._las.lims_project.OPEN_SCOPE_VISION2_HIPPOC: None,
                self._las.lims_project.OPEN_SCOPE_VISMO: None,
                self._las.lims_project.OPH5_X: None,
                self._las.lims_project.SLC6_A1_NEUROPIXEL: None,
                self._las.lims_project.SMART_SPIM_GENETIC_TOOLS: None,
                self._las.lims_project.SURGERY_X: None,
                self._las.lims_project.T301: None,
                self._las.lims_project.T301T: None,
                self._las.lims_project.T301_X: None,
                self._las.lims_project.T503: None,
                self._las.lims_project.T503_X: None,
                self._las.lims_project.T504: None,
                self._las.lims_project.T504_X: None,
                self._las.lims_project.T600: None,
                self._las.lims_project.T601: None,
                self._las.lims_project.T601_X: None,
                self._las.lims_project.TCYTX: None,
                self._las.lims_project.TASK_TRAINED_NETWORKS_MUL: None,
                self._las.lims_project.TASK_TRAINED_NETWORKS_NEU: None,
                self._las.lims_project.TEMPLETON_PSYCHEDELICS: None,
                self._las.lims_project.TEMPLETON_TTOC: None,
                self._las.lims_project.TINY_BLUE_DOT_BEHAVIOR: None,
                self._las.lims_project.U01_BFCT: None,
                self._las.lims_project.VARIABILITY_AIM1: None,
                self._las.lims_project.VARIABILITY_AIM1_PILOT: None,
                self._las.lims_project.VARIABILITY_SPONTANEOUS: None,
                self._las.lims_project.VI_DEEP_DIVE_EM_VOLUME: None,
                self._las.lims_project.VI_DEEPDLVE_DEEPSCOPE_PIE: None,
                self._las.lims_project.VIP_AXONAL_V1_PHASE1: None,
                self._las.lims_project.VIP_SOMATIC_V1_MESO: None,
                self._las.lims_project.VIP_SOMATIC_V1_PHASE1: None,
                self._las.lims_project.VIP_SOMATIC_V1_PHASE2: None,
                self._las.lims_project.VISUAL_BEHAVIOR: None,
                self._las.lims_project.VISUAL_BEHAVIOR_DEVELOPME: None,
                self._las.lims_project.VISUAL_BEHAVIOR_MULTISCOP: None,
                self._las.lims_project.VISUAL_BEHAVIOR_MULTI_001: None,
                self._las.lims_project.VISUAL_BEHAV_IOR_MULTISCO: None,
                self._las.lims_project.VISUAL_BEHAVIOR_TASK1_B: None,
            }.get(self._las.lims_project, None)
        )

    @property
    def aind_lims_workflow(self) -> Optional[Any]:
        """Maps lims_workflow to aind model"""
        return (
            None
            if self._las.lims_workflow is None
            else {
                self._las.lims_workflow.N_2P_SERIAL_IMAGING: None,
                self._las.lims_workflow.T6011_RETINA: None,
                self._las.lims_workflow.T6012A_RETROGRADE_CAV2_CR: None,
                self._las.lims_workflow.T6012B_RETROGRADE_RABIESG: None,
                self._las.lims_workflow.T6012C_RETROGRADE_FLUOROG: None,
                self._las.lims_workflow.T6013A_ANTEROGRADE_CRE_DE: None,
                self._las.lims_workflow.T6013B_ANTEROGRADE_CRE_DE: None,
                self._las.lims_workflow.T6014_ANTEROGRADE_TARGET: None,
                self._las.lims_workflow.T6015_TRANSSYNAPTIC: None,
                self._las.lims_workflow.SCREENING: None,
                self._las.lims_workflow.CHARACTERIZATION: None,
                self._las.lims_workflow.T5032_ANTEROGRADE_TARGET: None,
                self._las.lims_workflow.T5033_ALZHEIMERS_PLAQUE: None,
                self._las.lims_workflow.T5033_CONTROL: None,
                self._las.lims_workflow.T503_ANTEROGRADE_CREDEFIN: None,
                self._las.lims_workflow.MGT_ANTEROGRADE_PROJECTIO: None,
            }.get(self._las.lims_workflow, None)
        )

    @property
    def aind_lims_workflow_2(self) -> Optional[Any]:
        """Maps lims_workflow_2 to aind model"""
        return (
            None
            if self._las.lims_workflow_2 is None
            else {
                self._las.lims_workflow_2.N_2P_SERIAL_IMAGING: None,
                self._las.lims_workflow_2.T6011_RETINA: None,
                self._las.lims_workflow_2.T6012A_RETROGRADE_CAV2_CR: None,
                self._las.lims_workflow_2.T6012B_RETROGRADE_RABIESG: None,
                self._las.lims_workflow_2.T6012C_RETROGRADE_FLUOROG: None,
                self._las.lims_workflow_2.T6013A_ANTEROGRADE_CRE_DE: None,
                self._las.lims_workflow_2.T6013B_ANTEROGRADE_CRE_DE: None,
                self._las.lims_workflow_2.T6014_ANTEROGRADE_TARGET: None,
                self._las.lims_workflow_2.T6015_TRANSSYNAPTIC: None,
                self._las.lims_workflow_2.SCREENING: None,
                self._las.lims_workflow_2.CHARACTERIZATION: None,
                self._las.lims_workflow_2.T5032_ANTEROGRADE_TARGET: None,
                self._las.lims_workflow_2.T5033_ALZHEIMERS_PLAQUE: None,
                self._las.lims_workflow_2.T5033_CONTROL: None,
                self._las.lims_workflow_2.T503_ANTEROGRADE_CREDEFIN: None,
                self._las.lims_workflow_2.MGT_ANTEROGRADE_PROJECTIO: None,
            }.get(self._las.lims_workflow_2, None)
        )

    @property
    def aind_lt_task1(self) -> Optional[str]:
        """Maps lt_task1 to aind model"""
        return self._las.lt_task1

    @property
    def aind_lt_task2(self) -> Optional[str]:
        """Maps lt_task2 to aind model"""
        return self._las.lt_task2

    @property
    def aind_lt_task3(self) -> Optional[str]:
        """Maps lt_task3 to aind model"""
        return self._las.lt_task3

    @property
    def aind_lt_task4(self) -> Optional[str]:
        """Maps lt_task4 to aind model"""
        return self._las.lt_task4

    @property
    def aind_lt_task5(self) -> Optional[str]:
        """Maps lt_task5 to aind model"""
        return self._las.lt_task5

    @property
    def aind_modified(self) -> Optional[datetime]:
        """Maps modified to aind model"""
        return self._las.modified

    @property
    def aind_n_end_date(self) -> Optional[date]:
        """Maps n_end_date to aind model"""
        return self._parse_datetime_to_date(self._las.n_end_date)

    @property
    def aind_n_roid1(self) -> Optional[str]:
        """Maps n_roid1 to aind model"""
        return self._las.n_roid1

    @property
    def aind_n_roid2(self) -> Optional[str]:
        """Maps n_roid2 to aind model"""
        return self._las.n_roid2

    @property
    def aind_n_roid3(self) -> Optional[str]:
        """Maps n_roid3 to aind model"""
        return self._las.n_roid3

    @property
    def aind_n_roid4(self) -> Optional[str]:
        """Maps n_roid4 to aind model"""
        return self._las.n_roid4

    @property
    def aind_n_roid5(self) -> Optional[str]:
        """Maps n_roid5 to aind model"""
        return self._las.n_roid5

    @property
    def aind_n_start_date(self) -> Optional[date]:
        """Maps n_start_date to aind model"""
        return self._parse_datetime_to_date(self._las.n_start_date)

    @property
    def aind_oct(self) -> Optional[bool]:
        """Maps oct to aind model"""
        return self._las.oct

    @property
    def aind_post_fix(self) -> Optional[Any]:
        """Maps post_fix to aind model"""
        return (
            None
            if self._las.post_fix is None
            else {
                self._las.post_fix.N_10_SUCROSE: None,
                self._las.post_fix.N_10_SUCROSE_TO_30_SUCROS: None,
                self._las.post_fix.N_30_SUCROSE: None,
                self._las.post_fix.N_30_SUCROSE_FOILWRAPPED: None,
                self._las.post_fix.N_1X_PBS: None,
                self._las.post_fix.N_1X_PBS_FOILWRAPPED_TUBE: None,
                self._las.post_fix.N_1X_PBS_001_AZIDE: None,
                self._las.post_fix.N_1X_PBS_001_AZIDE_5M_L_T: None,
                self._las.post_fix.N_1X_PBS_001_AZIDE_FOILWR: None,
                self._las.post_fix.N_4PFA_TO_1X_PBS: None,
                self._las.post_fix.NUCLEASEFREE_1X_PBS_OM_FI: None,
                self._las.post_fix.NUCLEASEFREE_30_SUCROSE: None,
                self._las.post_fix.NUCLEASEFREE_30_SUCROSEFO: None,
                self._las.post_fix.OTHER_SPECIFY_BELOW: None,
            }.get(self._las.post_fix, None)
        )

    @property
    def aind_project_id(self) -> Optional[Any]:
        """Maps project_id to aind model"""
        return (
            None
            if self._las.project_id is None
            else {
                self._las.project_id.N_1010300110_COSTA_PGA_LA: None,
                self._las.project_id.N_1020100710_CTY_M_FISH: None,
                self._las.project_id.N_1020100910_CTY_MORPHOLO: None,
                self._las.project_id.N_1020101110_CTY_CONNECTO: None,
                self._las.project_id.N_1020101210_CTY_CONNECTO: None,
                self._las.project_id.N_1020101610_CTY_TAXONOMY: None,
                self._las.project_id.N_1020102720_CTY_BRAIN_AX: None,
                self._las.project_id.N_1020102920_CTY_BRAIN_CE: None,
                self._las.project_id.N_1020103120_W4_CTY_EU_HO: None,
                self._las.project_id.N_1020103120_W5_CTY_EU_HO: None,
                self._las.project_id.N_1020103220_CTY_MOUSE_AG: None,
                self._las.project_id.N_1020103620_CTY_DISSEMIN: None,
                self._las.project_id.N_1020104020_CTY_BRAIN_UG: None,
                self._las.project_id.N_1020104320_CTY_OPTICAL: None,
                self._las.project_id.N_1020104410_CTY_GENOMICS: None,
                self._las.project_id.N_1020104510_CTY_IVSCC: None,
                self._las.project_id.N_1020104620_CTY_WEILL_NE: None,
                self._las.project_id.N_1020104810_CTY_BARCODED: None,
                self._las.project_id.N_1020104920_CTY_OPIOID_T: None,
                self._las.project_id.N_1020105520_CTY_EM_MOTOR: None,
                self._las.project_id.N_1020105720_CTY_BRAIN_BG: None,
                self._las.project_id.N_1020105920_CTY_SCORCH: None,
                self._las.project_id.N_1020106020_CTY_BRAIN_DR: None,
                self._las.project_id.N_1020106120_CTY_BICAN_HU: None,
                self._las.project_id.N_1020106220_CTY_BICAN_MO: None,
                self._las.project_id.N_1020106410_CTY_GENETIC: None,
                self._las.project_id.N_1020106620_CTY_CONNECTS: None,
                self._las.project_id.N_1020106820_CTY_CONNECTS: None,
                self._las.project_id.N_1020106920_PRE_SPEND: None,
                self._las.project_id.N_1020107020_CTY_CONNECTS: None,
                self._las.project_id.N_1020199910_CTY_PROGRAM: None,
                self._las.project_id.N_1020200410_BTV_VISUAL_B: None,
                self._las.project_id.N_1020201220_BTV_BRAIN_VI: None,
                self._las.project_id.N_1020201620_MSP_BRAIN_MO: None,
                self._las.project_id.N_1020201720_BTV_BRAIN_NE: None,
                self._las.project_id.N_1020400410_OTH_MERITORI: None,
                self._las.project_id.N_1020400620_OTH_MEASURIN: None,
                self._las.project_id.N_1020400710_APLD_TARGETE: None,
                self._las.project_id.N_1020401010_CTY_SR_SLC6: None,
                self._las.project_id.N_1020401110_CTY_SR_SYNGA: None,
                self._las.project_id.N_1020401210_CTY_SR_FRIED: None,
                self._las.project_id.N_1020401410_CTY_PARKINSO: None,
                self._las.project_id.N_1028800310_ANIMAL_CARE: None,
                self._las.project_id.N_1028800510_TRANSGENIC_C: None,
                self._las.project_id.N_1028800810_LAB_ANIMAL_S: None,
                self._las.project_id.N_1060100110_IMMUNOLOGY_D: None,
                self._las.project_id.N_1210101620_MSP_BRAIN_OP: None,
                self._las.project_id.N_1210101820_MSP_EPHAPTIC: None,
                self._las.project_id.N_1210102320_MSP_TEMPLETO: None,
                self._las.project_id.N_1210102520_MSP_U01_BRID: None,
                self._las.project_id.N_1210102620_MSP_TEMPLETO: None,
                self._las.project_id.N_1220100110_AIND_SCIENTI: None,
                self._las.project_id.N_1220100220_MOLECULAR_CO: None,
                self._las.project_id.N_1220100220_PROJECT_1: None,
                self._las.project_id.N_1220100220_PROJECT_2: None,
                self._las.project_id.N_1220100220_PROJECT_4: None,
                self._las.project_id.N_1220100420_AIND_BRAINST: None,
                self._las.project_id.N_1220101020_AIND_POO_SIM: None,
                self._las.project_id.N_1220101120_AIND_COHEN_J: None,
                self._las.project_id.N_1220101220_AIND_RF1_FUN: None,
                self._las.project_id.N_1220101420_AIND_SIEGLE: None,
                self._las.project_id.N_1220101310_MSP_SCIENTIF: None,
                self._las.project_id.N_1220101920_AIND_CZI_COL: None,
                self._las.project_id.N_1220102020_AIND_COHEN_B: None,
                self._las.project_id.N_1220102020_AIBS_COHEN_B: None,
                self._las.project_id.N_1229999910_NEURAL_DYNAM: None,
                self._las.project_id.N_1250100110_SEA_HUB_SCIE: None,
                self._las.project_id.AAV_PRODUCTION_1028800410: None,
                self._las.project_id.RD_1028800410: None,
            }.get(self._las.project_id, None)
        )

    @property
    def aind_protocol(self) -> Optional[str]:
        """Maps protocol to aind model"""
        return (
            None
            if self._las.protocol is None
            else {
                self._las.protocol.N_2103_OPTICAL_PHYSIOLOGY: (
                    IacucProtocol.N_2103.value
                ),
                self._las.protocol.N_2104_ELECTROPHYSIOLOGY: (
                    IacucProtocol.N_2104.value
                ),
                self._las.protocol.N_2105_CHARACTERIZATION_O: (
                    IacucProtocol.N_2105.value
                ),
                self._las.protocol.N_2106_ANALYSIS_OF_INTEGR: (
                    IacucProtocol.N_2106.value
                ),
                self._las.protocol.N_2107_CIRCUIT_TRACING_AN: (
                    IacucProtocol.N_2107.value
                ),
                self._las.protocol.N_2109_ANALYSIS_OF_BRAIN: (
                    IacucProtocol.N_2109.value
                ),
                self._las.protocol.N_2110_SPECIFICITY_AND_ST: (
                    IacucProtocol.N_2110.value
                ),
                self._las.protocol.N_2112_CHARACTERIZATION_O: (
                    IacucProtocol.N_2112.value
                ),
                self._las.protocol.N_2113_IN_VITRO_SINGLE_CE: (
                    IacucProtocol.N_2113.value
                ),
                self._las.protocol.N_2114_CHARACTERIZATION_O: (
                    IacucProtocol.N_2114.value
                ),
                self._las.protocol.N_2115_OPTICAL_PHYSIOLOGY: (
                    IacucProtocol.N_2115.value
                ),
                self._las.protocol.N_2116_MOUSE_BREEDING: (
                    IacucProtocol.N_2116.value
                ),
                self._las.protocol.N_2117_OPEN_SCOPE_MINDSCO: (
                    IacucProtocol.N_2117.value
                ),
                self._las.protocol.N_2118_ANIMAL_HOLDING_AND: (
                    IacucProtocol.N_2118.value
                ),
                self._las.protocol.N_2119_TRAINING_AND_QUALI: (
                    IacucProtocol.N_2119.value
                ),
                self._las.protocol.N_2120_ANALYSIS_OF_GENE_E: (
                    IacucProtocol.N_2120.value
                ),
                self._las.protocol.N_2201_INTERROGATING_PROJ: (
                    IacucProtocol.N_2201.value
                ),
                self._las.protocol.N_2202_TESTING_AA_VS_IN_P: (
                    IacucProtocol.N_2202.value
                ),
                self._las.protocol.N_2204_PRIMARY_NEURON_AND: (
                    IacucProtocol.N_2204.value
                ),
                self._las.protocol.N_2205_OPTIMIZATION_AND_V: (
                    IacucProtocol.N_2205.value
                ),
                self._las.protocol.N_2207_IN_VITRO_BRAIN_STI: (
                    IacucProtocol.N_2207.value
                ),
                self._las.protocol.N_2212_INVESTIGATING_BRAI: (
                    IacucProtocol.N_2212.value
                ),
                self._las.protocol.N_2301_TESTING_OF_ENHANCE: (
                    IacucProtocol.N_2301.value
                ),
                self._las.protocol.N_2304_NEUROSURGERY_BEHAV: (
                    IacucProtocol.N_2304.value
                ),
                self._las.protocol.N_2305_IN_VIVO_BRAIN_STIM: (
                    IacucProtocol.N_2305.value
                ),
                self._las.protocol.N_2306_PATCHSEQ_CHARACTER: (
                    IacucProtocol.N_2306.value
                ),
                self._las.protocol.N_2307_DISSECTING_THE_NEU: (
                    IacucProtocol.N_2307.value
                ),
                self._las.protocol.N_2308_INDUCTION_OF_IMMUN: (
                    IacucProtocol.N_2308.value
                ),
                self._las.protocol.N_2401_THE_USE_OF_MICE_FO: (
                    IacucProtocol.N_2401.value
                ),
                self._las.protocol.N_2402_BRAIN_OBSERVATORY: (
                    IacucProtocol.N_2402.value
                ),
                self._las.protocol.N_2405_ANALYSIS_OF_INTEGR: (
                    IacucProtocol.N_2405.value
                ),
                self._las.protocol.N_2406_CHARACTERIZATION_OF_MOUS: (
                    IacucProtocol.N_2406.value
                ),
                self._las.protocol.N_2412_CIRCUIT_TRACING_AND_OPT: (
                    IacucProtocol.N_2412.value
                ),
            }.get(self._las.protocol, None)
        )

    @property
    def aind_qc_door_sheet(self) -> Optional[bool]:
        """Maps qc_door_sheet to aind model"""
        return self._las.qc_door_sheet

    @property
    def aind_req_age1(self) -> Optional[str]:
        """Maps req_age1 to aind model"""
        return self._las.req_age1

    @property
    def aind_req_age2(self) -> Optional[str]:
        """Maps req_age2 to aind model"""
        return self._las.req_age2

    @property
    def aind_req_age3(self) -> Optional[str]:
        """Maps req_age3 to aind model"""
        return self._las.req_age3

    @property
    def aind_req_pro1(self) -> Optional[LASProcedure]:
        """Maps req_pro1 to aind model"""
        return (
            None
            if self._las.req_pro1 is None
            else {
                self._las.req_pro1.TISSUE_COLLECTION: (
                    LASProcedure.TISSUE_COLLECTION
                ),
                self._las.req_pro1.INDUCTION: LASProcedure.INDUCTION,
                self._las.req_pro1.DOSING: LASProcedure.DOSING,
                self._las.req_pro1.RETRO_ORBITAL_INJECTION: (
                    LASProcedure.RETRO_ORBITAL_INJECTION
                ),
                self._las.req_pro1.INTRACEREBROVENTRICULAR_I: (
                    LASProcedure.IC_INJECTION
                ),
                self._las.req_pro1.BLOOD_COLLECTION: (
                    LASProcedure.BLOOD_COLLECTION
                ),
                self._las.req_pro1.CEREBROSPINAL_FLUID_COLLE: (
                    LASProcedure.CEREBROSPINAL_FLUID
                ),
                self._las.req_pro1.OTHER: LASProcedure.OTHER,
            }.get(self._las.req_pro1, None)
        )

    @property
    def aind_req_pro2(self) -> Optional[LASProcedure]:
        """Maps req_pro2 to aind model"""
        return (
            None
            if self._las.req_pro2 is None
            else {
                self._las.req_pro2.TISSUE_COLLECTION: (
                    LASProcedure.TISSUE_COLLECTION
                ),
                self._las.req_pro2.INDUCTION: LASProcedure.INDUCTION,
                self._las.req_pro2.DOSING: LASProcedure.DOSING,
                self._las.req_pro2.RETRO_ORBITAL_INJECTION: (
                    LASProcedure.RETRO_ORBITAL_INJECTION
                ),
                self._las.req_pro2.INTRACEREBROVENTRICULAR_I: (
                    LASProcedure.IC_INJECTION
                ),
                self._las.req_pro2.BLOOD_COLLECTION: (
                    LASProcedure.BLOOD_COLLECTION
                ),
                self._las.req_pro2.CEREBROSPINAL_FLUID_COLLE: (
                    LASProcedure.CEREBROSPINAL_FLUID
                ),
                self._las.req_pro2.OTHER: LASProcedure.OTHER,
            }.get(self._las.req_pro2, None)
        )

    @property
    def aind_req_pro3(self) -> Optional[LASProcedure]:
        """Maps req_pro3 to aind model"""
        return (
            None
            if self._las.req_pro3 is None
            else {
                self._las.req_pro3.TISSUE_COLLECTION: (
                    LASProcedure.TISSUE_COLLECTION
                ),
                self._las.req_pro3.INDUCTION: (LASProcedure.INDUCTION),
                self._las.req_pro3.DOSING: (LASProcedure.DOSING),
                self._las.req_pro3.RETRO_ORBITAL_INJECTION: (
                    LASProcedure.RETRO_ORBITAL_INJECTION
                ),
                self._las.req_pro3.INTRACEREBROVENTRICULAR_I: (
                    LASProcedure.IC_INJECTION
                ),
                self._las.req_pro3.BLOOD_COLLECTION: (
                    LASProcedure.BLOOD_COLLECTION
                ),
                self._las.req_pro3.CEREBROSPINAL_FLUID_COLLE: (
                    LASProcedure.CEREBROSPINAL_FLUID
                ),
                self._las.req_pro3.OTHER: LASProcedure.OTHER,
            }.get(self._las.req_pro3, None)
        )

    @property
    def aind_reqdate1(self) -> Optional[date]:
        """Maps reqdate1 to aind model"""
        return self._parse_datetime_to_date(self._las.reqdate1)

    @property
    def aind_reqdate2(self) -> Optional[date]:
        """Maps reqdate2 to aind model"""
        return self._parse_datetime_to_date(self._las.reqdate2)

    @property
    def aind_reqdate3(self) -> Optional[date]:
        """Maps reqdate3 to aind model"""
        return self._parse_datetime_to_date(self._las.reqdate3)

    @property
    def aind_request_status2(self) -> Optional[Any]:
        """Maps request_status2 to aind model"""
        return (
            None
            if self._las.request_status2 is None
            else {
                self._las.request_status2.NEW: None,
                self._las.request_status2.IN_PROGRESS: None,
                self._las.request_status2.COMPLETE: None,
                self._las.request_status2.CANCELLED: None,
            }.get(self._las.request_status2, None)
        )

    @property
    def aind_ro_box1(self) -> Optional[str]:
        """Maps ro_box1 to aind model"""
        return self._las.ro_box1

    @property
    def aind_ro_box2(self) -> Optional[str]:
        """Maps ro_box2 to aind model"""
        return self._las.ro_box2

    @property
    def aind_ro_box3(self) -> Optional[str]:
        """Maps ro_box3 to aind model"""
        return self._las.ro_box3

    @property
    def aind_ro_box4(self) -> Optional[str]:
        """Maps ro_box4 to aind model"""
        return self._las.ro_box4

    @property
    def aind_ro_box5(self) -> Optional[str]:
        """Maps ro_box5 to aind model"""
        return self._las.ro_box5

    @property
    def aind_ro_comment(self) -> Optional[str]:
        """Maps ro_comment to aind model"""
        return self._las.ro_comment

    @property
    def aind_ro_discard(self) -> Optional[bool]:
        """Maps ro_discard to aind model"""
        return self._las.ro_discard

    @property
    def aind_ro_eye1(self) -> Optional[Any]:
        """Maps ro_eye1 to aind model"""
        return (
            None
            if self._las.ro_eye1 is None
            else {
                self._las.ro_eye1.BEHIND_EITHER: None,
                self._las.ro_eye1.BEHIND_RIGHT: Side.RIGHT,
                self._las.ro_eye1.BEHIND_LEFT: Side.LEFT,
            }.get(self._las.ro_eye1, None)
        )

    @property
    def aind_ro_eye2(self) -> Optional[Any]:
        """Maps ro_eye2 to aind model"""
        return (
            None
            if self._las.ro_eye2 is None
            else {
                self._las.ro_eye2.BEHIND_EITHER: None,
                self._las.ro_eye2.BEHIND_RIGHT: Side.RIGHT,
                self._las.ro_eye2.BEHIND_LEFT: Side.LEFT,
            }.get(self._las.ro_eye2, None)
        )

    @property
    def aind_ro_eye3(self) -> Optional[Any]:
        """Maps ro_eye3 to aind model"""
        return (
            None
            if self._las.ro_eye3 is None
            else {
                self._las.ro_eye3.BEHIND_EITHER: None,
                self._las.ro_eye3.BEHIND_RIGHT: Side.RIGHT,
                self._las.ro_eye3.BEHIND_LEFT: Side.LEFT,
            }.get(self._las.ro_eye3, None)
        )

    @property
    def aind_ro_eye4(self) -> Optional[Any]:
        """Maps ro_eye4 to aind model"""
        return (
            None
            if self._las.ro_eye4 is None
            else {
                self._las.ro_eye4.BEHIND_EITHER: None,
                self._las.ro_eye4.BEHIND_RIGHT: Side.RIGHT,
                self._las.ro_eye4.BEHIND_LEFT: Side.LEFT,
            }.get(self._las.ro_eye4, None)
        )

    @property
    def aind_ro_eye5(self) -> Optional[Any]:
        """Maps ro_eye5 to aind model"""
        return (
            None
            if self._las.ro_eye5 is None
            else {
                self._las.ro_eye5.BEHIND_EITHER: None,
                self._las.ro_eye5.BEHIND_RIGHT: Side.RIGHT,
                self._las.ro_eye5.BEHIND_LEFT: Side.LEFT,
            }.get(self._las.ro_eye5, None)
        )

    @property
    def aind_ro_gc1(self) -> Optional[str]:
        """Maps ro_gc1 to aind model"""
        return self._las.ro_gc1

    @property
    def aind_ro_gc1b(self) -> Optional[str]:
        """Maps ro_gc1b to aind model"""
        return self._las.ro_gc1b

    @property
    def aind_ro_gc1c(self) -> Optional[str]:
        """Maps ro_gc1c to aind model"""
        return self._las.ro_gc1c

    @property
    def aind_ro_gc1d(self) -> Optional[str]:
        """Maps ro_gc1d to aind model"""
        return self._las.ro_gc1d

    @property
    def aind_ro_gc2(self) -> Optional[str]:
        """Maps ro_gc2 to aind model"""
        return self._las.ro_gc2

    @property
    def aind_ro_gc2b(self) -> Optional[str]:
        """Maps ro_gc2b to aind model"""
        return self._las.ro_gc2b

    @property
    def aind_ro_gc2c(self) -> Optional[str]:
        """Maps ro_gc2c to aind model"""
        return self._las.ro_gc2c

    @property
    def aind_ro_gc2d(self) -> Optional[str]:
        """Maps ro_gc2d to aind model"""
        return self._las.ro_gc2d

    @property
    def aind_ro_gc3(self) -> Optional[str]:
        """Maps ro_gc3 to aind model"""
        return self._las.ro_gc3

    @property
    def aind_ro_gc3b(self) -> Optional[str]:
        """Maps ro_gc3b to aind model"""
        return self._las.ro_gc3b

    @property
    def aind_ro_gc3c(self) -> Optional[str]:
        """Maps ro_gc3c to aind model"""
        return self._las.ro_gc3c

    @property
    def aind_ro_gc3d(self) -> Optional[str]:
        """Maps ro_gc3d to aind model"""
        return self._las.ro_gc3d

    @property
    def aind_ro_gc4(self) -> Optional[str]:
        """Maps ro_gc4 to aind model"""
        return self._las.ro_gc4

    @property
    def aind_ro_gc4b(self) -> Optional[str]:
        """Maps ro_gc4b to aind model"""
        return self._las.ro_gc4b

    @property
    def aind_ro_gc4c(self) -> Optional[str]:
        """Maps ro_gc4c to aind model"""
        return self._las.ro_gc4c

    @property
    def aind_ro_gc4d(self) -> Optional[str]:
        """Maps ro_gc4d to aind model"""
        return self._las.ro_gc4d

    @property
    def aind_ro_gc5(self) -> Optional[str]:
        """Maps ro_gc5 to aind model"""
        return self._las.ro_gc5

    @property
    def aind_ro_gc5b(self) -> Optional[str]:
        """Maps ro_gc5b to aind model"""
        return self._las.ro_gc5b

    @property
    def aind_ro_gc5c(self) -> Optional[str]:
        """Maps ro_gc5c to aind model"""
        return self._las.ro_gc5c

    @property
    def aind_ro_gc5d(self) -> Optional[str]:
        """Maps ro_gc5d to aind model"""
        return self._las.ro_gc5d

    @property
    def aind_ro_ice(self) -> Optional[bool]:
        """Maps ro_ice to aind model"""
        return self._las.ro_ice

    @property
    def aind_ro_lims(self) -> Optional[Any]:
        """Maps ro_lims to aind model"""
        return (
            None
            if self._las.ro_lims is None
            else {
                self._las.ro_lims.STEREOTAXIC_INJECTIONS: None,
                self._las.ro_lims.NEW_STEREOTAXIC_INJECTION: None,
            }.get(self._las.ro_lims, None)
        )

    @property
    def aind_ro_lot1(self) -> Optional[str]:
        """Maps ro_lot1 to aind model"""
        return self._las.ro_lot1

    @property
    def aind_ro_lot1b(self) -> Optional[str]:
        """Maps ro_lot1b to aind model"""
        return self._las.ro_lot1b

    @property
    def aind_ro_lot1c(self) -> Optional[str]:
        """Maps ro_lot1c to aind model"""
        return self._las.ro_lot1c

    @property
    def aind_ro_lot1d(self) -> Optional[str]:
        """Maps ro_lot1d to aind model"""
        return self._las.ro_lot1d

    @property
    def aind_ro_lot2(self) -> Optional[str]:
        """Maps ro_lot2 to aind model"""
        return self._las.ro_lot2

    @property
    def aind_ro_lot2b(self) -> Optional[str]:
        """Maps ro_lot2b to aind model"""
        return self._las.ro_lot2b

    @property
    def aind_ro_lot2c(self) -> Optional[str]:
        """Maps ro_lot2c to aind model"""
        return self._las.ro_lot2c

    @property
    def aind_ro_lot2d(self) -> Optional[str]:
        """Maps ro_lot2d to aind model"""
        return self._las.ro_lot2d

    @property
    def aind_ro_lot3(self) -> Optional[str]:
        """Maps ro_lot3 to aind model"""
        return self._las.ro_lot3

    @property
    def aind_ro_lot3b(self) -> Optional[str]:
        """Maps ro_lot3b to aind model"""
        return self._las.ro_lot3b

    @property
    def aind_ro_lot3c(self) -> Optional[str]:
        """Maps ro_lot3c to aind model"""
        return self._las.ro_lot3c

    @property
    def aind_ro_lot3d(self) -> Optional[str]:
        """Maps ro_lot3d to aind model"""
        return self._las.ro_lot3d

    @property
    def aind_ro_lot4(self) -> Optional[str]:
        """Maps ro_lot4 to aind model"""
        return self._las.ro_lot4

    @property
    def aind_ro_lot4b(self) -> Optional[str]:
        """Maps ro_lot4b to aind model"""
        return self._las.ro_lot4b

    @property
    def aind_ro_lot4c(self) -> Optional[str]:
        """Maps ro_lot4c to aind model"""
        return self._las.ro_lot4c

    @property
    def aind_ro_lot4d(self) -> Optional[str]:
        """Maps ro_lot4d to aind model"""
        return self._las.ro_lot4d

    @property
    def aind_ro_lot5(self) -> Optional[str]:
        """Maps ro_lot5 to aind model"""
        return self._las.ro_lot5

    @property
    def aind_ro_lot5b(self) -> Optional[str]:
        """Maps ro_lot5b to aind model"""
        return self._las.ro_lot5b

    @property
    def aind_ro_lot5c(self) -> Optional[str]:
        """Maps ro_lot5c to aind model"""
        return self._las.ro_lot5c

    @property
    def aind_ro_lot5d(self) -> Optional[str]:
        """Maps ro_lot5d to aind model"""
        return self._las.ro_lot5d

    @property
    def aind_ro_sop(self) -> Optional[Any]:
        """Maps ro_sop to aind model"""
        return (
            None
            if self._las.ro_sop is None
            else {
                self._las.ro_sop.AF0131_RETROORBITAL_INJEC: None,
                self._las.ro_sop.AF0139_RETROORBITAL_INJEC: None,
            }.get(self._las.ro_sop, None)
        )

    @property
    def aind_ro_spin_down(self) -> Optional[bool]:
        """Maps ro_spin_down to aind model"""
        return self._las.ro_spin_down

    @property
    def aind_ro_sub1(self) -> Optional[str]:
        """Maps ro_sub1 to aind model"""
        return self._las.ro_sub1

    @property
    def aind_ro_sub1b(self) -> Optional[str]:
        """Maps ro_sub1b to aind model"""
        return self._las.ro_sub1b

    @property
    def aind_ro_sub1c(self) -> Optional[str]:
        """Maps ro_sub1c to aind model"""
        return self._las.ro_sub1c

    @property
    def aind_ro_sub1d(self) -> Optional[str]:
        """Maps ro_sub1d to aind model"""
        return self._las.ro_sub1d

    @property
    def aind_ro_sub2(self) -> Optional[str]:
        """Maps ro_sub2 to aind model"""
        return self._las.ro_sub2

    @property
    def aind_ro_sub2b(self) -> Optional[str]:
        """Maps ro_sub2b to aind model"""
        return self._las.ro_sub2b

    @property
    def aind_ro_sub2c(self) -> Optional[str]:
        """Maps ro_sub2c to aind model"""
        return self._las.ro_sub2c

    @property
    def aind_ro_sub2d(self) -> Optional[str]:
        """Maps ro_sub2d to aind model"""
        return self._las.ro_sub2d

    @property
    def aind_ro_sub3(self) -> Optional[str]:
        """Maps ro_sub3 to aind model"""
        return self._las.ro_sub3

    @property
    def aind_ro_sub3b(self) -> Optional[str]:
        """Maps ro_sub3b to aind model"""
        return self._las.ro_sub3b

    @property
    def aind_ro_sub3c(self) -> Optional[str]:
        """Maps ro_sub3c to aind model"""
        return self._las.ro_sub3c

    @property
    def aind_ro_sub3d(self) -> Optional[str]:
        """Maps ro_sub3d to aind model"""
        return self._las.ro_sub3d

    @property
    def aind_ro_sub4(self) -> Optional[str]:
        """Maps ro_sub4 to aind model"""
        return self._las.ro_sub4

    @property
    def aind_ro_sub4b(self) -> Optional[str]:
        """Maps ro_sub4b to aind model"""
        return self._las.ro_sub4b

    @property
    def aind_ro_sub4c(self) -> Optional[str]:
        """Maps ro_sub4c to aind model"""
        return self._las.ro_sub4c

    @property
    def aind_ro_sub4d(self) -> Optional[str]:
        """Maps ro_sub4d to aind model"""
        return self._las.ro_sub4d

    @property
    def aind_ro_sub5(self) -> Optional[str]:
        """Maps ro_sub5 to aind model"""
        return self._las.ro_sub5

    @property
    def aind_ro_sub5b(self) -> Optional[str]:
        """Maps ro_sub5b to aind model"""
        return self._las.ro_sub5b

    @property
    def aind_ro_sub5c(self) -> Optional[str]:
        """Maps ro_sub5c to aind model"""
        return self._las.ro_sub5c

    @property
    def aind_ro_sub5d(self) -> Optional[str]:
        """Maps ro_sub5d to aind model"""
        return self._las.ro_sub5d

    @property
    def aind_ro_tite1(self) -> Optional[str]:
        """Maps ro_tite1 to aind model"""
        return self._las.ro_tite1

    @property
    def aind_ro_tite1b(self) -> Optional[str]:
        """Maps ro_tite1b to aind model"""
        return self._las.ro_tite1b

    @property
    def aind_ro_tite1c(self) -> Optional[str]:
        """Maps ro_tite1c to aind model"""
        return self._las.ro_tite1c

    @property
    def aind_ro_tite1d(self) -> Optional[str]:
        """Maps ro_tite1d to aind model"""
        return self._las.ro_tite1d

    @property
    def aind_ro_tite2(self) -> Optional[str]:
        """Maps ro_tite2 to aind model"""
        return self._las.ro_tite2

    @property
    def aind_ro_tite2b(self) -> Optional[str]:
        """Maps ro_tite2b to aind model"""
        return self._las.ro_tite2b

    @property
    def aind_ro_tite2c(self) -> Optional[str]:
        """Maps ro_tite2c to aind model"""
        return self._las.ro_tite2c

    @property
    def aind_ro_tite2d(self) -> Optional[str]:
        """Maps ro_tite2d to aind model"""
        return self._las.ro_tite2d

    @property
    def aind_ro_tite3(self) -> Optional[str]:
        """Maps ro_tite3 to aind model"""
        return self._las.ro_tite3

    @property
    def aind_ro_tite3b(self) -> Optional[str]:
        """Maps ro_tite3b to aind model"""
        return self._las.ro_tite3b

    @property
    def aind_ro_tite3c(self) -> Optional[str]:
        """Maps ro_tite3c to aind model"""
        return self._las.ro_tite3c

    @property
    def aind_ro_tite3d(self) -> Optional[str]:
        """Maps ro_tite3d to aind model"""
        return self._las.ro_tite3d

    @property
    def aind_ro_tite4(self) -> Optional[str]:
        """Maps ro_tite4 to aind model"""
        return self._las.ro_tite4

    @property
    def aind_ro_tite4b(self) -> Optional[str]:
        """Maps ro_tite4b to aind model"""
        return self._las.ro_tite4b

    @property
    def aind_ro_tite4c(self) -> Optional[str]:
        """Maps ro_tite4c to aind model"""
        return self._las.ro_tite4c

    @property
    def aind_ro_tite4d(self) -> Optional[str]:
        """Maps ro_tite4d to aind model"""
        return self._las.ro_tite4d

    @property
    def aind_ro_tite5(self) -> Optional[str]:
        """Maps ro_tite5 to aind model"""
        return self._las.ro_tite5

    @property
    def aind_ro_tite5b(self) -> Optional[str]:
        """Maps ro_tite5b to aind model"""
        return self._las.ro_tite5b

    @property
    def aind_ro_tite5c(self) -> Optional[str]:
        """Maps ro_tite5c to aind model"""
        return self._las.ro_tite5c

    @property
    def aind_ro_tite5d(self) -> Optional[str]:
        """Maps ro_tite5d to aind model"""
        return self._las.ro_tite5d

    @property
    def aind_ro_tube1(self) -> Optional[str]:
        """Maps ro_tube1 to aind model"""
        return self._las.ro_tube1

    @property
    def aind_ro_tube2(self) -> Optional[str]:
        """Maps ro_tube2 to aind model"""
        return self._las.ro_tube2

    @property
    def aind_ro_tube3(self) -> Optional[str]:
        """Maps ro_tube3 to aind model"""
        return self._las.ro_tube3

    @property
    def aind_ro_tube4(self) -> Optional[str]:
        """Maps ro_tube4 to aind model"""
        return self._las.ro_tube4

    @property
    def aind_ro_tube5(self) -> Optional[str]:
        """Maps ro_tube5 to aind model"""
        return self._las.ro_tube5

    @property
    def aind_ro_vol1(self) -> Optional[Decimal]:
        """Maps ro_vol1 to aind model"""
        return self._parse_basic_decimal_str(self._las.ro_vol1)

    @property
    def aind_ro_vol2(self) -> Optional[Decimal]:
        """Maps ro_vol2 to aind model"""
        return self._parse_basic_decimal_str(self._las.ro_vol2)

    @property
    def aind_ro_vol3(self) -> Optional[Decimal]:
        """Maps ro_vol3 to aind model"""
        return self._parse_basic_decimal_str(self._las.ro_vol3)

    @property
    def aind_ro_vol4(self) -> Optional[Decimal]:
        """Maps ro_vol4 to aind model"""
        return self._parse_basic_decimal_str(self._las.ro_vol4)

    @property
    def aind_ro_vol5(self) -> Optional[Decimal]:
        """Maps ro_vol5 to aind model"""
        return self._parse_basic_decimal_str(self._las.ro_vol5)

    @property
    def aind_ro_vol_v1(self) -> Optional[Decimal]:
        """Maps ro_vol_v1 to aind model"""
        return self._parse_basic_decimal_str(self._las.ro_vol_v1)

    @property
    def aind_ro_vol_v1b(self) -> Optional[str]:
        """Maps ro_vol_v1b to aind model"""
        return self._parse_basic_decimal_str(self._las.ro_vol_v1b)

    @property
    def aind_ro_vol_v1c(self) -> Optional[str]:
        """Maps ro_vol_v1c to aind model"""
        return self._las.ro_vol_v1c

    @property
    def aind_ro_vol_v1d(self) -> Optional[str]:
        """Maps ro_vol_v1d to aind model"""
        return self._las.ro_vol_v1d

    @property
    def aind_ro_vol_v2(self) -> Optional[str]:
        """Maps ro_vol_v2 to aind model"""
        return self._las.ro_vol_v2

    @property
    def aind_ro_vol_v2b(self) -> Optional[str]:
        """Maps ro_vol_v2b to aind model"""
        return self._las.ro_vol_v2b

    @property
    def aind_ro_vol_v2c(self) -> Optional[str]:
        """Maps ro_vol_v2c to aind model"""
        return self._las.ro_vol_v2c

    @property
    def aind_ro_vol_v2d(self) -> Optional[str]:
        """Maps ro_vol_v2d to aind model"""
        return self._las.ro_vol_v2d

    @property
    def aind_ro_vol_v3(self) -> Optional[str]:
        """Maps ro_vol_v3 to aind model"""
        return self._las.ro_vol_v3

    @property
    def aind_ro_vol_v3b(self) -> Optional[str]:
        """Maps ro_vol_v3b to aind model"""
        return self._las.ro_vol_v3b

    @property
    def aind_ro_vol_v3c(self) -> Optional[str]:
        """Maps ro_vol_v3c to aind model"""
        return self._las.ro_vol_v3c

    @property
    def aind_ro_vol_v3d(self) -> Optional[str]:
        """Maps ro_vol_v3d to aind model"""
        return self._las.ro_vol_v3d

    @property
    def aind_ro_vol_v4(self) -> Optional[str]:
        """Maps ro_vol_v4 to aind model"""
        return self._las.ro_vol_v4

    @property
    def aind_ro_vol_v4b(self) -> Optional[str]:
        """Maps ro_vol_v4b to aind model"""
        return self._las.ro_vol_v4b

    @property
    def aind_ro_vol_v4c(self) -> Optional[str]:
        """Maps ro_vol_v4c to aind model"""
        return self._las.ro_vol_v4c

    @property
    def aind_ro_vol_v4d(self) -> Optional[str]:
        """Maps ro_vol_v4d to aind model"""
        return self._las.ro_vol_v4d

    @property
    def aind_ro_vol_v5(self) -> Optional[str]:
        """Maps ro_vol_v5 to aind model"""
        return self._las.ro_vol_v5

    @property
    def aind_ro_vol_v5b(self) -> Optional[str]:
        """Maps ro_vol_v5b to aind model"""
        return self._las.ro_vol_v5b

    @property
    def aind_ro_vol_v5c(self) -> Optional[str]:
        """Maps ro_vol_v5c to aind model"""
        return self._las.ro_vol_v5c

    @property
    def aind_ro_vol_v5d(self) -> Optional[str]:
        """Maps ro_vol_v5d to aind model"""
        return self._las.ro_vol_v5d

    @property
    def aind_ro_where(self) -> Optional[Any]:
        """Maps ro_where to aind model"""
        return (
            None
            if self._las.ro_where is None
            else {
                self._las.ro_where.LAS_BLUE_BIN_IN_VIVARIUM: None,
                self._las.ro_where.OTHER_TYPE_IN: None,
            }.get(self._las.ro_where, None)
        )

    @property
    def aind_spec_deli_loc(self) -> Optional[str]:
        """Maps spec_deli_loc to aind model"""
        return self._las.spec_deli_loc

    @property
    def aind_species(self) -> Optional[Any]:
        """Maps species to aind model"""
        return (
            None
            if self._las.species is None
            else {
                self._las.species.MOUSE: None,
                self._las.species.RAT: None,
            }.get(self._las.species, None)
        )

    @property
    def aind_tam(self) -> Optional[bool]:
        """Maps tam to aind model"""
        return self._las.tam

    @property
    def aind_tam_age(self) -> Optional[str]:
        """Maps tam_age to aind model"""
        return self._las.tam_age

    @property
    def aind_tam_freq(self) -> Optional[Any]:
        """Maps tam_freq to aind model"""
        return (
            None
            if self._las.tam_freq is None
            else {
                self._las.tam_freq.STANDARD_5_DAY_DOSE: None,
                self._las.tam_freq.SINGLE_DOSE: None,
                self._las.tam_freq.OTHER_TYPE_IN: None,
            }.get(self._las.tam_freq, None)
        )

    @property
    def aind_title(self) -> Optional[str]:
        """Maps title to aind model"""
        return self._las.title

    @property
    def aind_tmp(self) -> Optional[bool]:
        """Maps tmp to aind model"""
        return self._las.tmp

    @property
    def aind_tmp_age(self) -> Optional[str]:
        """Maps tmp_age to aind model"""
        return self._las.tmp_age

    @property
    def aind_tmp_freq(self) -> Optional[Any]:
        """Maps tmp_freq to aind model"""
        return (
            None
            if self._las.tmp_freq is None
            else {
                self._las.tmp_freq.STANDARD_3_DAY_DOSE: None,
                self._las.tmp_freq.SINGLE_DOSE: None,
                self._las.tmp_freq.OTHER_TYPEIN: None,
            }.get(self._las.tmp_freq, None)
        )

    @property
    def aind_ui_version_string(self) -> Optional[str]:
        """Maps ui_version_string to aind model"""
        return self._las.ui_version_string

    @property
    def aind_wellness_report_no_x002_f(self) -> Optional[bool]:
        """Maps wellness_report_no_x002_f to aind model"""
        return self._las.wellness_report_no_x002_f

    @property
    def aind_whereto_obtainsubstance_i(self) -> Optional[Any]:
        """Maps whereto_obtainsubstance_i to aind model"""
        return (
            None
            if self._las.whereto_obtainsubstance_i is None
            else {
                self._las.whereto_obtainsubstance_i.LAS_BLUE_BIN_IN_VIVARIUM: (
                    None
                ),
                self._las.whereto_obtainsubstance_i.OTHER_SPECIFY_BELOW: None,
            }.get(self._las.whereto_obtainsubstance_i, None)
        )

    def has_ip_injection(self) -> bool:
        """Is there an IP injection procedure?"""
        return (
            LASProcedure.DOSING
            in [self.aind_req_pro1, self.aind_req_pro2, self.aind_req_pro3]
            and self.aind_dose_route == Doseroute.INTRAPERITONEAL_IP
        )

    def has_ro_injection(self) -> bool:
        """Is there a retro-orbital injection?"""
        return LASProcedure.RETRO_ORBITAL_INJECTION in [
            self.aind_req_pro1,
            self.aind_req_pro2,
            self.aind_req_pro3,
        ]

    def _map_injectable_materials(
        self, material_num: int
    ) -> List[InjectableMaterial]:
        """
        Maps injectable materials based on the material_num.
        Parameters
        ----------
        material_num : int
            The ro injection substance number
        Returns
        -------
            List[InjectableMaterial]
        """
        materials = []
        suffixes = ["", "b", "c", "d"]
        for suffix in suffixes:
            material_attr = f"aind_ro_sub{material_num}{suffix}"
            if getattr(self, material_attr, None):
                materials.append(
                    InjectableMaterial(
                        substance=getattr(self, material_attr),
                        prep_lot_id=getattr(
                            self, f"aind_ro_lot{material_num}{suffix}", None
                        ),
                        genome_copy=getattr(
                            self, f"aind_ro_gc{material_num}{suffix}", None
                        ),
                        titer=getattr(
                            self, f"aind_ro_tite{material_num}{suffix}", None
                        ),
                        virus_volume=getattr(
                            self, f"aind_ro_vol_v{material_num}{suffix}", None
                        ),
                    )
                )
        return materials

    def map_ro_injection_info(self, ro_num: int) -> RetroOrbitalInjectionInfo:
        """
        Compiles retro-orbital injection information from LAS data
        Parameters
        ----------
        ro_num : int
             Retro orbital injection number
        Returns
        -------
        RetroOrbitalInjectionInfo
        class RetroOrbitalInjectionInfo:
        """
        if ro_num == 1:
            return RetroOrbitalInjectionInfo(
                animal_id=self.aind_n_roid1,
                injection_eye=self.aind_ro_eye1,
                injection_volume=self.aind_ro_vol1,
                tube_label=self.aind_ro_tube1,
                box_label=self.aind_ro_box1,
                injectable_materials=self._map_injectable_materials(
                    material_num=1
                ),
            )
        elif ro_num == 2:
            return RetroOrbitalInjectionInfo(
                animal_id=self.aind_n_roid2,
                injection_eye=self.aind_ro_eye2,
                injection_volume=self.aind_ro_vol2,
                tube_label=self.aind_ro_tube2,
                box_label=self.aind_ro_box2,
                injectable_materials=self._map_injectable_materials(
                    material_num=2
                ),
            )
        elif ro_num == 3:
            return RetroOrbitalInjectionInfo(
                animal_id=self.aind_n_roid3,
                injection_eye=self.aind_ro_eye3,
                injection_volume=self.aind_ro_vol3,
                tube_label=self.aind_ro_tube3,
                box_label=self.aind_ro_box3,
                injectable_materials=self._map_injectable_materials(
                    material_num=3
                ),
            )
        elif ro_num == 4:
            return RetroOrbitalInjectionInfo(
                animal_id=self.aind_n_roid4,
                injection_eye=self.aind_ro_eye4,
                injection_volume=self.aind_ro_vol4,
                tube_label=self.aind_ro_tube4,
                box_label=self.aind_ro_box4,
                injectable_materials=self._map_injectable_materials(
                    material_num=4
                ),
            )
        elif ro_num == 5:
            return RetroOrbitalInjectionInfo(
                animal_id=self.aind_n_roid5,
                injection_eye=self.aind_ro_eye5,
                injection_volume=self.aind_ro_vol5,
                tube_label=self.aind_ro_tube5,
                box_label=self.aind_ro_box5,
                injectable_materials=self._map_injectable_materials(
                    material_num=5
                ),
            )

    def map_viral_materials(
        self, injectable_materials: List[InjectableMaterial]
    ):
        """Maps injectable material to viral material"""
        # TODO: map injectable material info in case tars gets no response
        viral_materials = []
        for material in injectable_materials:
            titer, unit = self._parse_titer(getattr(material, "titer", None))
            viral_materials.append(
                ViralMaterial.model_construct(
                    name=material.prep_lot_id, titer=titer, titer_unit=unit
                )
            )
        return viral_materials

    def get_procedure(self, subject_id) -> Optional[Surgery]:
        """Return Surgery as best as possible from a record."""
        subject_procedures = []
        if self.has_ip_injection():
            ip_injection = IntraperitonealInjection.model_construct(
                injection_materials=(
                    [self.aind_dose_sub] if self.aind_dose_sub else []
                ),
                injection_volume=self.aind_dosevolume,
                injection_duration=self.aind_doseduration,
            )
            subject_procedures.append(ip_injection)
        if self.has_ro_injection():
            # Check if there are ro injections in 1 thorugh 5
            for ro_num in range(1, 6):
                ro_info = self.map_ro_injection_info(ro_num=ro_num)
                if ro_info.animal_id == subject_id:
                    injection_materials = self.map_viral_materials(
                        injectable_materials=ro_info.injectable_materials
                    )
                    ro_injection = RetroOrbitalInjection.model_construct(
                        injection_volume=ro_info.injection_volume,
                        injection_eye=ro_info.injection_eye,
                        injection_materials=injection_materials,
                    )
                    subject_procedures.append(ro_injection)
        if subject_procedures:
            name = (
                self.aind_author_id
                if self.aind_author_id
                else self.aind_author_lookup_id
            )
            return Surgery.model_construct(
                experimenter_full_name=name,
                iacuc_protocol=self.aind_protocol,
                start_date=self.aind_n_start_date,
                end_date=self.aind_n_end_date,
                procedures=subject_procedures,
            )
        else:
            return None
