"""ISO channel naming lookup tables for crash test instrumentation.

Based on SAE J211-1 and ISO 13499 conventions. These tables map the positional
codes in a 16-character channel name to human-readable descriptions.
"""

from __future__ import annotations

# ---------------------------------------------------------------------------
# Test Object codes (positions 1-2)
# First digit: row/category, Second digit: seat position or object type
# ---------------------------------------------------------------------------
TEST_OBJECTS: dict[str, str] = {
    # Sled tests
    "01": "Sled Occupant",
    # Vehicle structure
    "10": "Vehicle Structure",
    # First row occupants
    "11": "Driver (1st Row Left)",
    "12": "Front Passenger (1st Row Right)",
    # Second row
    "13": "2nd Row Left",
    "14": "2nd Row Center",
    "15": "2nd Row Right",
    # Third row
    "16": "3rd Row Left",
    "17": "3rd Row Center",
    "18": "3rd Row Right",
    # Barrier / impactor
    "20": "Barrier / Impactor",
    "21": "Moving Deformable Barrier",
    # Pedestrian
    "30": "Pedestrian / Headform Impactor",
    "31": "Pedestrian Upper Legform",
    "32": "Pedestrian Lower Legform",
    # Barrier object codes (ISO 13499)
    "B0": "Barrier",
    "B1": "Barrier Row 1",
    "B2": "Barrier Row 2",
    # Impactor codes
    "D0": "Impactor",
    "D1": "Impactor 1",
    "D2": "Impactor 2",
}

# ---------------------------------------------------------------------------
# Main Location codes (positions 3-6)
# ---------------------------------------------------------------------------
MAIN_LOCATIONS: dict[str, str] = {
    # Head / Neck
    "HEAD": "Head",
    "SKULL": "Skull",
    "FACE": "Face",
    "NECK": "Neck",
    "NCKL": "Neck Lower",
    "NCKU": "Neck Upper",
    # Thorax
    "CHST": "Chest",
    "THSP": "Thoracic Spine",
    "CLAV": "Clavicle",
    "RIBS": "Ribs",
    "STRN": "Sternum",
    "SHLR": "Shoulder",
    "SHLD": "Shoulder",
    "SHLL": "Shoulder Left",
    "SHLR": "Shoulder Right",
    # Spine
    "SPIN": "Spine",
    "LUSP": "Lumbar Spine",
    # Abdomen / Pelvis
    "ABDO": "Abdomen",
    "PELV": "Pelvis",
    "ILAC": "Iliac Crest",
    "SACR": "Sacrum",
    "PUBC": "Pubic Symphysis",
    # Upper extremities
    "SHLD": "Shoulder",
    "UPRA": "Upper Arm",
    "ELBO": "Elbow",
    "FORA": "Forearm",
    "WRST": "Wrist",
    "HAND": "Hand",
    # Lower extremities
    "FEMR": "Femur",
    "KNEE": "Knee",
    "TIBI": "Tibia",
    "ANKL": "Ankle",
    "FOOT": "Foot",
    # Vehicle structure locations
    "STCL": "Steering Column",
    "STRW": "Steering Wheel",
    "DASH": "Dashboard / IP",
    "BPIL": "B-Pillar",
    "APIL": "A-Pillar",
    "CPIL": "C-Pillar",
    "DOOR": "Door",
    "DRIM": "Door Trim",
    "SEAT": "Seat",
    "STTK": "Seat Track",
    "BELT": "Seat Belt",
    "FLOR": "Floor",
    "ROOF": "Roof",
    "FIRE": "Firewall",
    "TOEP": "Toepan / Footwell",
    "INST": "Instrument Panel",
    "PEDB": "Pedal Box",
    "BRKP": "Brake Pedal",
    "ACCP": "Accelerator Pedal",
    "CLTP": "Clutch Pedal",
    # Vehicle general
    "VEHC": "Vehicle (General)",
    "ENGN": "Engine",
    "BATT": "Battery",
    "FUEL": "Fuel System",
    # Barrier
    "BARR": "Barrier",
    "BFAC": "Barrier Face",
    # Foot / toes
    "TOES": "Toes",
    # Belt positions
    "BLOP": "Belt (Lap/Shoulder)",
    # Wheel
    "WHEL": "Wheel",
    # Structural — additional
    "FORA": "Floor Rail",
    "FBAR": "Barrier Face",
    "KNSL": "Knee Slider",
    # Simulation / other
    "SIMN": "Simulation Node",
    "OTHR": "Other",
    "0000": "General / Unknown",
}

# ---------------------------------------------------------------------------
# Fine Location codes (positions 7-10)
# ---------------------------------------------------------------------------
FINE_LOCATIONS: dict[str, str] = {
    "0000": "Center of Gravity / Primary",
    "00UP": "Upper",
    "UP00": "Upper",
    "00LO": "Lower",
    "LO00": "Lower",
    "00LE": "Left",
    "LE00": "Left",
    "00RI": "Right",
    "RI00": "Right",
    "00FR": "Front",
    "FR00": "Front",
    "00RE": "Rear",
    "RE00": "Rear",
    "00IN": "Inner",
    "IN00": "Inner",
    "00OU": "Outer",
    "OU00": "Outer",
    "LEUP": "Left Upper",
    "RIUP": "Right Upper",
    "LELO": "Left Lower",
    "RILO": "Right Lower",
    "LETP": "Left Proximal",
    "RITP": "Right Proximal",
    "LETD": "Left Distal",
    "RITD": "Right Distal",
    # Rib positions (THOR / ES-2re)
    "RB01": "Rib 1",
    "RB02": "Rib 2",
    "RB03": "Rib 3",
    "RB04": "Rib 4",
    "RB05": "Rib 5",
    "RB06": "Rib 6",
    # Spine vertebrae
    "T001": "T1 Vertebra",
    "T004": "T4 Vertebra",
    "T008": "T8 Vertebra",
    "T012": "T12 Vertebra",
    "L001": "L1 Vertebra",
    "L002": "L2 Vertebra",
    "L003": "L3 Vertebra",
    "L005": "L5 Vertebra",
    # THOR IR-TRACC positions
    "ULXX": "Upper Left",
    "URXX": "Upper Right",
    "LLXX": "Lower Left",
    "LRXX": "Lower Right",
    # Tibia positions (real MME data uses these)
    "LEUP": "Left Upper",
    "RIUP": "Right Upper",
    "LELO": "Left Lower",
    "RILO": "Right Lower",
    # Fine location with number suffix
    "0001": "Secondary",
    "0100": "Lower Position",
    "0101": "Lower Secondary",
}

# ---------------------------------------------------------------------------
# Physical Measurement codes (positions 11-12)
# ---------------------------------------------------------------------------
MEASUREMENTS: dict[str, tuple[str, str]] = {
    # (description, typical SI unit)
    "AC": ("Acceleration", "m/s²"),
    "FO": ("Force", "N"),
    "MO": ("Moment", "N·m"),
    "DS": ("Displacement", "mm"),
    "DC": ("Deflection", "mm"),
    "VE": ("Velocity", "m/s"),
    "AN": ("Angle", "deg"),
    "AV": ("Angular Velocity", "deg/s"),
    "AA": ("Angular Acceleration", "rad/s²"),
    "PR": ("Pressure", "kPa"),
    "TE": ("Temperature", "°C"),
    "ST": ("Strain", "µε"),
    "EN": ("Energy", "J"),
    "PW": ("Power", "W"),
    "VO": ("Voltage", "V"),
    "CU": ("Current", "A"),
    "TI": ("Time", "s"),
}

# ---------------------------------------------------------------------------
# Direction / Axis codes (position 13)
# ---------------------------------------------------------------------------
DIRECTIONS: dict[str, str] = {
    "X": "X (Longitudinal)",
    "Y": "Y (Lateral)",
    "Z": "Z (Vertical)",
    "R": "Resultant",
}

# SAE J211 axis sign conventions (positive direction)
SAE_SIGN_CONVENTIONS: dict[str, str] = {
    "X": "Forward (positive fore)",
    "Y": "Right (positive starboard)",
    "Z": "Downward (positive down)",
}

# ---------------------------------------------------------------------------
# Sense codes (position 14)
# ---------------------------------------------------------------------------
SENSE_CODES: dict[str, str] = {
    "A": "SAE Sign Convention A",
    "P": "Positive (SAE)",
    "N": "Negative",
    "V": "Vehicle Reference",
    "0": "Unsigned / Scalar",
}

# ---------------------------------------------------------------------------
# CFC Filter classes — mapping class number to -3dB cutoff frequency
# Per SAE J211-1: f_cutoff = CFC * (5/3)
# ---------------------------------------------------------------------------
CFC_CLASSES: dict[int, float] = {
    60: 100.0,
    180: 300.0,
    600: 1000.0,
    1000: 1650.0,
}

CFC_MINIMUM_SAMPLE_RATES: dict[int, float] = {
    60: 800.0,
    180: 2000.0,
    600: 6667.0,
    1000: 10000.0,
}

# ---------------------------------------------------------------------------
# Common dummy types and their identifiers
# ---------------------------------------------------------------------------
DUMMY_TYPES: dict[str, str] = {
    "H3-50M": "Hybrid III 50th Percentile Male",
    "H3-05F": "Hybrid III 5th Percentile Female",
    "H3-95M": "Hybrid III 95th Percentile Male",
    "THOR-50M": "THOR 50th Percentile Male",
    "SID-IIs": "SID-IIs (Side Impact)",
    "ES-2re": "ES-2re (Side Impact)",
    "WSID-50": "WorldSID 50th Percentile",
    "Q1.5": "Q1.5 Child Dummy (18 months)",
    "Q3": "Q3 Child Dummy (3 years)",
    "Q6": "Q6 Child Dummy (6 years)",
    "Q10": "Q10 Child Dummy (10 years)",
    "CRABI": "CRABI 12-Month Infant",
}

# ---------------------------------------------------------------------------
# Unit normalization — map common non-SI labels to standard forms
# ---------------------------------------------------------------------------
UNIT_ALIASES: dict[str, str] = {
    "g": "g",
    "G": "g",
    "m/s2": "m/s²",
    "m/s^2": "m/s²",
    "N": "N",
    "kN": "kN",
    "Nm": "N·m",
    "N.m": "N·m",
    "N*m": "N·m",
    "mm": "mm",
    "m": "m",
    "cm": "cm",
    "m/s": "m/s",
    "km/h": "km/h",
    "deg": "deg",
    "rad": "rad",
    "deg/s": "deg/s",
    "rad/s": "rad/s",
    "rad/s2": "rad/s²",
    "rad/s^2": "rad/s²",
    "kPa": "kPa",
    "bar": "bar",
    "Pa": "Pa",
    "C": "°C",
    "degC": "°C",
    "°C": "°C",
    "V": "V",
    "A": "A",
    "J": "J",
    "W": "W",
    "microstrain": "µε",
    "µε": "µε",
    "ue": "µε",
}


def normalize_unit(raw_unit: str) -> str:
    """Normalize a unit string to a standard form."""
    stripped = raw_unit.strip()
    return UNIT_ALIASES.get(stripped, stripped)
