# target_simulator/gui/ppi_adapter.py

from typing import Dict, List, Optional
import math
from target_simulator.core.models import Target
from target_simulator.analysis.simulation_state_hub import SimulationStateHub


def build_display_data(
    simulation_hub: SimulationStateHub,
    scenario: Optional["Scenario"] = None,
    engine: Optional["SimulationEngine"] = None,
    ppi_widget: Optional["PPIDisplay"] = None,
    logger: Optional["Logger"] = None,
) -> Dict[str, List[Target]]:
    """
    Builds PPI display data from the simulation hub, converting absolute
    'real' coordinates to relative coordinates based on the ownship's position.

    Returns a dict with keys 'simulated' and 'real' containing lightweight
    Target objects suitable for passing to PPIDisplay.
    """
    simulated_targets_for_ppi: List[Target] = []
    real_targets_for_ppi: List[Target] = []

    if not simulation_hub:
        return {"simulated": [], "real": []}

    # Get ownship state for coordinate transformation
    ownship_state = simulation_hub.get_ownship_state()
    ownship_pos_xy_ft = ownship_state.get("position_xy_ft")

    target_ids = simulation_hub.get_all_target_ids()

    for tid in target_ids:
        history = simulation_hub.get_target_history(tid)
        if not history:
            continue

        # --- Process Simulated Data (assumed to be relative) ---
        if history.get("simulated"):
            # Simulated data is generated relative to (0,0), so no transformation is needed.
            last_sim_state = history["simulated"][-1]

            # Unpack the state tuple, now expecting velocities
            if len(last_sim_state) >= 6:
                _ts, x_ft, y_ft, z_ft, vel_fps, vert_vel_fps = last_sim_state[:6]
            else:  # Fallback for old data format
                _ts, x_ft, y_ft, z_ft = last_sim_state
                vel_fps, vert_vel_fps = 0.0, 0.0

            sim_target = Target(target_id=tid, trajectory=[])
            setattr(sim_target, "_pos_x_ft", x_ft)
            setattr(sim_target, "_pos_y_ft", y_ft)
            setattr(sim_target, "_pos_z_ft", z_ft)
            sim_target.current_velocity_fps = vel_fps
            sim_target.current_vertical_velocity_fps = vert_vel_fps
            sim_target._update_current_polar_coords()

            # Preserve heading information from the engine/scenario if available
            try:
                heading = None
                if engine and getattr(engine, "scenario", None):
                    t = engine.scenario.get_target(tid)
                    if t:
                        heading = getattr(t, "current_heading_deg", None)
                if heading is None and scenario:
                    t2 = scenario.get_target(tid)
                    if t2:
                        heading = getattr(t2, "current_heading_deg", None)
                if heading is not None:
                    sim_target.current_heading_deg = float(heading)
            except Exception:
                pass

            # Preserve active flag
            sim_target.active = True
            if engine and getattr(engine, "scenario", None):
                t_engine = engine.scenario.get_target(tid)
                if t_engine is not None:
                    sim_target.active = bool(getattr(t_engine, "active", True))

            simulated_targets_for_ppi.append(sim_target)

        # --- Process Real Data (transforming from absolute to relative) ---
        if history.get("real"):
            last_real_state = history["real"][-1]
            _ts, abs_x_ft, abs_y_ft, abs_z_ft = last_real_state[:4]

            rel_x_ft, rel_y_ft = abs_x_ft, abs_y_ft
            if ownship_pos_xy_ft:
                # Calculate position relative to the ownship
                rel_x_ft = abs_x_ft - ownship_pos_xy_ft[0]
                rel_y_ft = abs_y_ft - ownship_pos_xy_ft[1]

            # The z-coordinate (altitude) is typically absolute, but for display
            # we can treat it as relative to the ownship's altitude.
            ownship_alt_ft = ownship_state.get("altitude_ft", 0.0)
            rel_z_ft = abs_z_ft - ownship_alt_ft

            real_target = Target(target_id=tid, trajectory=[])
            setattr(real_target, "_pos_x_ft", rel_x_ft)
            setattr(real_target, "_pos_y_ft", rel_y_ft)
            setattr(real_target, "_pos_z_ft", rel_z_ft)
            real_target._update_current_polar_coords()

            # Copy last-known heading if hub provides it
            hdg = simulation_hub.get_real_heading(tid)
            if hdg is not None:
                real_target.current_heading_deg = float(hdg) % 360

            real_target.active = True
            real_targets_for_ppi.append(real_target)

    if logger:
        logger.debug(
            "PPI Adapter: Built display data (simulated=%d, real=%d)",
            len(simulated_targets_for_ppi),
            len(real_targets_for_ppi),
        )

    return {"simulated": simulated_targets_for_ppi, "real": real_targets_for_ppi}
