"""
Right-side information panel — fully responsive.
  • Large heading display
  • Data fields (HDG T, ROT, PITCH, ROLL, VAR, HEAVE, YAW RATE)
  • ROT arc indicator
  • Boat attitude silhouettes (pitch / roll / yaw)
  • Touch buttons
"""
import math
from PyQt5.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout,
                              QLabel, QPushButton, QFrame, QSizePolicy)
from PyQt5.QtCore    import Qt, pyqtSignal, QRectF, QPointF
from PyQt5.QtGui     import (QFont, QPainter, QPen, QBrush,
                              QColor, QPainterPath)
import ui.styles as S


# ─────────────────────────────────────────────────────────────────────────────
# Info Panel
# ─────────────────────────────────────────────────────────────────────────────

class InfoPanel(QWidget):

    night_toggled    = pyqtSignal(bool)
    port_requested   = pyqtSignal()
    hdg_mode_changed = pyqtSignal(str)   # 'M' or 'T'

    def __init__(self, parent=None):
        super().__init__(parent)
        self._night    = False
        self._hdg_mode = 'M'
        self._build()

    # ── Layout ─────────────────────────────────────────────────────────────────

    def _build(self):
        root = QVBoxLayout(self)
        root.setContentsMargins(4, 4, 4, 4)
        root.setSpacing(4)
        self._root_layout = root

        # Large magnetic heading
        self.hdg_val = QLabel('---.-°M')
        self.hdg_val.setAlignment(Qt.AlignCenter)
        self.hdg_val.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Ignored)
        root.addWidget(self.hdg_val, stretch=4)

        # Data rows
        self._rows = {}
        fields = [
            ('HDG (T)',  'hdg_t',   '---.-°T'),
            ('ROT',      'rot',     '--- °/min'),
            ('PITCH',    'pitch',   '+--.-°'),
            ('ROLL',     'roll',    '+--.-°'),
            ('VAR',      'var',     '--.-°-'),
            ('HEAVE',    'accel_z', '--.- m/s²'),
            ('YAW RATE', 'gyro_z',  '--.- °/s'),
        ]
        rows_wrap = QWidget()
        rows_wrap.setObjectName('section_box')
        rows_vl = QVBoxLayout(rows_wrap)
        rows_vl.setContentsMargins(0, 0, 0, 0)
        rows_vl.setSpacing(0)
        for label, key, default in fields:
            row, val = self._field_row(label, default)
            self._rows[key] = val
            rows_vl.addWidget(row)
        root.addWidget(rows_wrap, stretch=3 * 7)

        # ROT arc
        self.rot_arc = RotArc()
        self.rot_arc.setObjectName('section_box')
        root.addWidget(self.rot_arc, stretch=5)

        # Boat attitude silhouettes
        import config
        self.boat_att = BoatAttitudeWidget(vessel_type=config.VESSEL_TYPE)
        self.boat_att.setObjectName('section_box')
        root.addWidget(self.boat_att, stretch=7)

        # Touch buttons
        self._btn_container = QWidget()
        self._btn_container.setObjectName('section_box')
        self._btn_layout = QHBoxLayout(self._btn_container)
        self._btn_hdg   = self._btn('HDG °M', self._toggle_hdg_mode)
        self._btn_night = self._btn('NIGHT',  self._toggle_night)
        self._btn_port  = self._btn('PORTS',  self.port_requested.emit)
        self._btn_layout.addWidget(self._btn_hdg)
        self._btn_layout.addWidget(self._btn_night)
        self._btn_layout.addWidget(self._btn_port)
        root.addWidget(self._btn_container, stretch=2)

        self._apply_theme()

    def _field_row(self, label_text, default):
        row = QWidget()
        row.setObjectName('field_row')
        hl = QHBoxLayout(row)
        hl.setContentsMargins(0, 0, 0, 0)
        lbl = QLabel(label_text)
        lbl.setObjectName('field_lbl')
        lbl.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
        val = QLabel(default)
        val.setObjectName('field_val')
        val.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
        hl.addWidget(lbl, stretch=4)
        hl.addWidget(val, stretch=6)
        return row, val

    def _divider(self):
        line = QFrame()
        line.setFrameShape(QFrame.HLine)
        line.setFixedHeight(1)
        line.setStyleSheet(f'background: {S.DIVIDER.name()};')
        return line

    def _btn(self, text, callback):
        b = QPushButton(text)
        b.setObjectName('nav_btn')
        b.clicked.connect(callback)
        return b

    # ── Theme ──────────────────────────────────────────────────────────────────

    def _apply_theme(self):
        n      = self._night
        bg     = S.N_BG.name()    if n else S.PANEL_BG.name()
        gold   = S.N_GOLD.name()  if n else S.GOLD.name()
        bright = S.N_GOLD.name()  if n else S.GOLD_BRIGHT.name()
        white  = S.N_WHITE.name() if n else S.WHITE.name()
        dim    = S.N_WHITE.name() if n else S.WHITE_DIM.name()
        box_bg = S.BEZEL_DARK.name()

        h = max(self.height(), 480)
        w = max(self.width(),  200)

        hdg_fs  = max(14, h // 12)
        data_fs = max(10, h // 38)
        lbl_fs  = max(9,  h // 48)
        btn_fs  = max(9,  h // 50)
        btn_h   = max(36, h // 14)
        pad_h   = max(2,  h // 120)
        pad_w   = max(6,  w // 25)
        btn_sp  = max(3,  w // 60)
        btn_rad = max(4,  h // 100)
        gap     = max(4,  h // 120)   # spacing between frames
        brad    = max(4,  h // 140)   # border radius for section boxes

        self._root_layout.setContentsMargins(gap, gap, gap, gap)
        self._root_layout.setSpacing(gap)
        self._btn_layout.setContentsMargins(btn_sp, btn_sp, btn_sp, btn_sp)
        self._btn_layout.setSpacing(btn_sp)

        self.setStyleSheet(f"""
            QWidget {{
                background: {bg};
                color: {white};
                font-family: 'Courier New';
            }}
            QWidget#section_box {{
                background: {box_bg};
                border: 1px solid {S.DIVIDER.name()};
                border-radius: {brad}px;
            }}
            QWidget#field_row {{
                border-bottom: 1px solid {S.DIVIDER.name()};
            }}
            QLabel#field_lbl {{
                color: {dim};
                font-size: {lbl_fs}px;
                font-weight: bold;
                padding-left: {pad_w}px;
                padding-top: {pad_h}px;
                padding-bottom: {pad_h}px;
            }}
            QLabel#field_val {{
                color: {white};
                font-size: {data_fs}px;
                padding-right: {pad_w}px;
                padding-top: {pad_h}px;
                padding-bottom: {pad_h}px;
            }}
            QPushButton#nav_btn {{
                background: {S.BEZEL_MID.name()};
                color: {gold};
                border: 1px solid {gold};
                border-radius: {btn_rad}px;
                font-size: {btn_fs}px;
                font-weight: bold;
                min-height: {btn_h}px;
            }}
            QPushButton#nav_btn:pressed {{
                background: {gold};
                color: {bg};
            }}
        """)

        f = QFont('Courier New', hdg_fs, QFont.Bold)
        self.hdg_val.setFont(f)
        self.hdg_val.setStyleSheet(f'color: {bright}; background: transparent;')

        self.rot_arc.set_night(n)
        self.boat_att.set_night(n)

    def resizeEvent(self, event):
        super().resizeEvent(event)
        self._apply_theme()

    # ── Data update ────────────────────────────────────────────────────────────

    def update_data(self, nav):
        if self._hdg_mode == 'T':
            hdg    = nav.hdg_true_calc
            suffix = '°T'
        else:
            hdg    = nav.hdg_mag
            suffix = '°M'
        self.hdg_val.setText(f'{hdg:05.1f}{suffix}' if hdg is not None else f'---.--{suffix}')
        self._set('hdg_t',   self._fmt_hdg(nav.hdg_true_calc, '°T'))
        self._set('rot',     self._fmt_rot(nav.rot))
        self._set('pitch',   self._fmt_signed(nav.pitch,   '°'))
        self._set('roll',    self._fmt_signed(nav.roll,    '°'))
        self._set('var',     self._fmt_var(nav.variation))
        self._set('accel_z', self._fmt_accel(nav.accel_z))
        self._set('gyro_z',  self._fmt_gyro(nav.gyro_z))

        rot   = nav.rot   or 0.0
        pitch = nav.pitch or 0.0
        roll  = nav.roll  or 0.0

        self.rot_arc.set_rot(rot)
        self.boat_att.set_attitude(pitch, roll, rot)

    def _set(self, key, text):
        if key in self._rows:
            self._rows[key].setText(text)

    # ── Formatting ─────────────────────────────────────────────────────────────

    @staticmethod
    def _fmt_hdg(v, suffix):
        return f'{v:05.1f}{suffix}' if v is not None else f'---.--{suffix}'

    @staticmethod
    def _fmt_rot(v):
        return f'{v:+.1f} °/min' if v is not None else '--- °/min'

    @staticmethod
    def _fmt_signed(v, unit):
        return f'{v:+.1f}{unit}' if v is not None else f'+--.-{unit}'

    @staticmethod
    def _fmt_var(v):
        return f'{abs(v):.1f}°{"E" if v >= 0 else "W"}' if v is not None else '--.-°-'

    @staticmethod
    def _fmt_accel(v):
        return f'{v:+.2f} m/s²' if v is not None else '--.- m/s²'

    @staticmethod
    def _fmt_gyro(v):
        return f'{v:+.2f} °/s' if v is not None else '--.- °/s'

    # ── Toggles ────────────────────────────────────────────────────────────────

    def _toggle_hdg_mode(self):
        self._hdg_mode = 'T' if self._hdg_mode == 'M' else 'M'
        self._btn_hdg.setText(f'HDG °{self._hdg_mode}')
        self.hdg_mode_changed.emit(self._hdg_mode)

    def _toggle_night(self):
        self._night = not self._night
        self._apply_theme()
        self.night_toggled.emit(self._night)


# ─────────────────────────────────────────────────────────────────────────────
# ROT Arc
# ─────────────────────────────────────────────────────────────────────────────

class RotArc(QWidget):
    """Semicircular rate-of-turn indicator. Fully proportional."""

    def __init__(self, parent=None):
        super().__init__(parent)
        self._rot   = 0.0
        self._night = False

    def set_rot(self, rot):
        self._rot = rot or 0.0
        self.update()

    def set_night(self, on):
        self._night = on
        self.update()

    def paintEvent(self, event):
        p = QPainter(self)
        p.setRenderHint(QPainter.Antialiasing)
        w, h = self.width(), self.height()
        if w < 10 or h < 10:
            return

        gold  = S.N_GOLD  if self._night else S.GOLD
        white = S.N_WHITE if self._night else S.WHITE_DIM
        red   = S.N_RED   if self._night else S.RED
        blue  = S.N_BLUE  if self._night else S.BLUE

        # Reserve top & bottom padding so text doesn't touch dividers
        pad  = max(6, h * 0.10)
        cx   = w / 2.0
        cy   = h * 0.60
        r    = min(w * 0.40, (h - pad * 2) * 0.68)
        lw   = max(2.0, r * 0.07)

        # Grey track arc
        p.setPen(QPen(S.BEZEL_MID, lw, Qt.SolidLine, Qt.RoundCap))
        p.drawArc(int(cx - r), int(cy - r), int(r * 2), int(r * 2),
                  0, 180 * 16)

        # Colored ROT arc (scale: ±60°/min = full 90° sweep)
        rot_c = max(-60.0, min(60.0, self._rot))
        if abs(rot_c) > 0.3:
            span  = -(rot_c / 60.0) * 90.0
            color = blue if rot_c > 0 else red
            p.setPen(QPen(color, lw * 1.4, Qt.SolidLine, Qt.RoundCap))
            p.drawArc(int(cx - r), int(cy - r), int(r * 2), int(r * 2),
                      int(90 * 16), int(-span * 16))

        # Center tick
        p.setPen(QPen(gold, max(1.5, r * 0.04)))
        p.drawLine(int(cx), int(cy - r * 1.10), int(cx), int(cy - r * 0.88))

        # PORT / STBD labels — above the arc ends
        side_fs = max(7, int(r * 0.17))
        p.setFont(QFont('Arial', side_fs))
        p.setPen(QPen(white))
        side_h = max(14, int(r * 0.28))
        p.drawText(int(cx - r - r * 0.1), int(cy - r * 0.18),
                   int(r * 0.9), side_h, Qt.AlignCenter, 'PORT')
        p.drawText(int(cx + r * 0.2), int(cy - r * 0.18),
                   int(r * 0.9), side_h, Qt.AlignCenter, 'STBD')

        # ROT value — with gap below arc
        txt_fs = max(8, int(r * 0.22))
        txt_h  = max(16, int(r * 0.35))
        p.setFont(QFont('Courier New', txt_fs, QFont.Bold))
        p.setPen(QPen(white))
        p.drawText(0, int(cy + r * 0.18), w, txt_h,
                   Qt.AlignCenter, f'{self._rot:+.1f} °/min')


# ─────────────────────────────────────────────────────────────────────────────
# Boat Attitude Widget
# ─────────────────────────────────────────────────────────────────────────────

class BoatAttitudeWidget(QWidget):
    """
    Three animated boat silhouettes:
      PITCH  — side view, bow right, rotates fore/aft
      ROLL   — front view, tilts port/stbd
      YAW    — top view, rotates with ROT
    """

    def __init__(self, vessel_type: str = 'motor_cruiser', parent=None):
        super().__init__(parent)
        self._pitch       = 0.0
        self._roll        = 0.0
        self._rot         = 0.0
        self._night       = False
        self._vessel_type = vessel_type

    def set_attitude(self, pitch: float, roll: float, rot: float = 0.0):
        self._pitch = pitch
        self._roll  = roll
        self._rot   = rot
        self.update()

    def set_night(self, on: bool):
        self._night = on
        self.update()

    def paintEvent(self, event):
        p = QPainter(self)
        p.setRenderHint(QPainter.Antialiasing)
        p.setRenderHint(QPainter.TextAntialiasing)

        w, h = self.width(), self.height()
        if w < 30 or h < 20:
            return

        pw = w / 3.0   # panel width per silhouette

        self._draw_panel(p, 0,      pw, h, self._pitch,
                         'PITCH', 'side',  f'{self._pitch:+.1f}°')
        self._draw_panel(p, pw,     pw, h, self._roll,
                         'ROLL',  'front', f'{self._roll:+.1f}°')
        self._draw_panel(p, pw * 2, pw, h, self._rot,
                         'YAW',   'top',   f'{self._rot:+.1f}°/m')

    def _draw_panel(self, p, x, pw, h, value, label, view, val_str):
        gold  = S.N_GOLD    if self._night else S.GOLD
        white = S.N_WHITE   if self._night else S.WHITE
        dim   = S.N_WHITE   if self._night else S.WHITE_DIM

        mg   = max(3, int(pw * 0.06))
        lh   = max(14, int(h * 0.15))    # label height
        vh   = max(14, int(h * 0.15))    # value height
        boat_h = h - lh - vh

        cx  = x + pw / 2.0
        cy  = lh + boat_h / 2.0
        r   = min(pw * 0.42, boat_h * 0.44)

        # Panel bg
        p.setBrush(QBrush(S.BEZEL_DARK))
        p.setPen(QPen(S.DIVIDER, 1))
        p.drawRoundedRect(QRectF(x + mg, mg, pw - mg * 2, h - mg * 2),
                          max(3, mg * 0.6), max(3, mg * 0.6))

        # Label
        lfs = max(7, int(h * 0.085))
        p.setFont(QFont('Arial', lfs, QFont.Bold))
        p.setPen(QPen(gold))
        p.drawText(QRectF(x, mg, pw, lh), Qt.AlignCenter, label)

        # Waterline (fixed)
        p.setPen(QPen(dim.darker(180) if not self._night else dim.darker(120),
                      max(1, int(r * 0.03)), Qt.DashLine))
        p.drawLine(QPointF(x + mg * 2, cy), QPointF(x + pw - mg * 2, cy))

        # Rotated boat silhouette
        p.save()
        p.translate(cx, cy)

        vt = self._vessel_type
        if view == 'side':
            p.rotate(-value)
            if vt == 'cargo':      self._boat_side_cargo(p, r, gold)
            else:                  self._boat_side(p, r, gold)
        elif view == 'front':
            p.rotate(value)
            if vt == 'cargo':      self._boat_front_cargo(p, r, gold)
            else:                  self._boat_front(p, r, gold)
        elif view == 'top':
            vis = max(-45.0, min(45.0, value * 0.75))
            p.rotate(vis)
            if vt == 'cargo':      self._boat_top_cargo(p, r, gold)
            else:                  self._boat_top(p, r, gold)

        p.restore()

        # Value
        vfs = max(7, int(h * 0.10))
        p.setFont(QFont('Courier New', vfs, QFont.Bold))
        p.setPen(QPen(white))
        p.drawText(QRectF(x, h - vh - mg, pw, vh), Qt.AlignCenter, val_str)

    # ── Boat shapes ────────────────────────────────────────────────────────────

    def _boat_side(self, p, r, color):
        """Modern superyacht starboard profile — bow right, sleek low lines."""
        lw      = max(1.0, r * 0.025)
        h_fill  = color.darker(148)
        h_pen   = color.darker(185)
        c_fill  = color.darker(162)
        win_col = QColor(28, 48, 95, 220)

        # ── 1. HULL — sleek, low freeboard ────────────────────────
        hull = QPainterPath()
        hull.moveTo(-r*0.88, -r*0.10)     # transom top
        hull.lineTo(-r*0.92,  r*0.14)     # transom bottom
        hull.quadTo(-r*0.20,  r*0.30,  r*0.28,  r*0.22)
        hull.quadTo( r*0.68,  r*0.13,  r*0.94, -r*0.03)
        hull.lineTo( r*0.80, -r*0.28)     # bow deck
        hull.cubicTo(r*0.52, -r*0.22, r*0.04, -r*0.16, -r*0.30, -r*0.16)
        hull.lineTo(-r*0.88, -r*0.10)
        hull.closeSubpath()
        p.setPen(QPen(h_pen, lw))
        p.setBrush(QBrush(h_fill))
        p.drawPath(hull)

        # ── 2. RED BOOT STRIPE ─────────────────────────────────────
        boot = QPainterPath()
        boot.moveTo(-r*0.92,  r*0.14)
        boot.quadTo(-r*0.20,  r*0.20,  r*0.28,  r*0.14)
        boot.quadTo( r*0.68,  r*0.06,  r*0.94, -r*0.03)
        boot.lineTo( r*0.90,  r*0.02)
        boot.quadTo( r*0.66,  r*0.06,  r*0.24,  r*0.10)
        boot.quadTo(-r*0.20,  r*0.14, -r*0.92,  r*0.08)
        boot.closeSubpath()
        p.setPen(Qt.NoPen)
        p.setBrush(QBrush(QColor(172, 22, 22, 210)))
        p.drawPath(boot)

        # ── 3. MAIN SUPERSTRUCTURE — long, low, angular ───────────
        sup = QPainterPath()
        sup.moveTo(-r*0.76, -r*0.10)
        sup.lineTo(-r*0.76, -r*0.42)
        sup.lineTo(-r*0.70, -r*0.46)
        sup.lineTo( r*0.36, -r*0.46)
        sup.lineTo( r*0.44, -r*0.40)
        sup.lineTo( r*0.44, -r*0.10)
        sup.closeSubpath()
        p.setPen(QPen(h_pen, lw * 0.85))
        p.setBrush(QBrush(c_fill))
        p.drawPath(sup)

        # ── 4. LONG WINDOW STRIP ───────────────────────────────────
        p.setPen(QPen(color.darker(122), max(1, r*0.018)))
        p.setBrush(QBrush(win_col.lighter(140)))
        p.drawRoundedRect(QRectF(-r*0.72, -r*0.43, r*1.06, r*0.22),
                          r*0.016, r*0.016)

        # ── 5. BRIDGE DECK ─────────────────────────────────────────
        br = QPainterPath()
        br.moveTo(-r*0.38, -r*0.46)
        br.lineTo(-r*0.38, -r*0.68)
        br.lineTo(-r*0.32, -r*0.72)
        br.lineTo( r*0.26, -r*0.72)
        br.lineTo( r*0.32, -r*0.66)
        br.lineTo( r*0.32, -r*0.46)
        br.closeSubpath()
        p.setBrush(QBrush(c_fill.darker(112)))
        p.drawPath(br)
        p.setBrush(QBrush(win_col.lighter(160)))
        p.drawRoundedRect(QRectF(-r*0.32, -r*0.69, r*0.54, r*0.16),
                          r*0.012, r*0.012)

        # ── 6. MAST & RADAR ────────────────────────────────────────
        p.setPen(QPen(color.darker(128), max(1.5, r*0.028)))
        p.drawLine(QPointF(r*0.00, -r*0.72), QPointF(r*0.00, -r*0.95))
        p.setPen(QPen(h_pen, max(1, r*0.015)))
        p.setBrush(QBrush(color.darker(160)))
        p.drawEllipse(QPointF(r*0.00, -r*0.93), r*0.048, r*0.034)

        # ── 7. SWIM PLATFORM ───────────────────────────────────────
        plat = QPainterPath()
        plat.moveTo(-r*0.88, r*0.14)
        plat.lineTo(-r*0.98, r*0.14)
        plat.lineTo(-r*0.98, r*0.20)
        plat.lineTo(-r*0.88, r*0.20)
        plat.closeSubpath()
        p.setPen(QPen(h_pen, lw * 0.8))
        p.setBrush(QBrush(h_fill.darker(110)))
        p.drawPath(plat)

    def _boat_front(self, p, r, color):
        """Modern superyacht bow-on — deep-V hull, wide flare, low superstructure."""
        lw      = max(1.0, r * 0.025)
        h_fill  = color.darker(148)
        h_pen   = color.darker(185)
        c_fill  = color.darker(162)
        win_col = QColor(28, 48, 95, 220)

        # ── HULL below waterline — sharp V ─────────────────────────
        hull_v = QPainterPath()
        hull_v.moveTo( 0,       r*0.50)
        hull_v.lineTo(-r*0.52,  r*0.06)
        hull_v.lineTo( r*0.52,  r*0.06)
        hull_v.closeSubpath()
        p.setPen(QPen(h_pen, lw))
        p.setBrush(QBrush(h_fill.darker(118)))
        p.drawPath(hull_v)

        # ── HULL TOPSIDES — wide flare ─────────────────────────────
        hull_t = QPainterPath()
        hull_t.moveTo(-r*0.52,  r*0.06)
        hull_t.quadTo(-r*0.84, -r*0.02, -r*0.88, -r*0.16)
        hull_t.lineTo(-r*0.62, -r*0.24)
        hull_t.lineTo( 0,      -r*0.32)
        hull_t.lineTo( r*0.62, -r*0.24)
        hull_t.lineTo( r*0.88, -r*0.16)
        hull_t.quadTo( r*0.84, -r*0.02,  r*0.52,  r*0.06)
        hull_t.closeSubpath()
        p.setPen(QPen(h_pen, lw))
        p.setBrush(QBrush(h_fill))
        p.drawPath(hull_t)

        # Boot stripe
        p.setPen(QPen(QColor(172, 22, 22, 210), max(2.0, r*0.034)))
        p.drawLine(QPointF(-r*0.52, r*0.06), QPointF(r*0.52, r*0.06))

        # ── WINDSHIELD — wide, angled ──────────────────────────────
        ws = QPainterPath()
        ws.moveTo(-r*0.26, -r*0.32)
        ws.lineTo(-r*0.20, -r*0.58)
        ws.lineTo( 0,      -r*0.64)
        ws.lineTo( r*0.20, -r*0.58)
        ws.lineTo( r*0.26, -r*0.32)
        ws.closeSubpath()
        p.setPen(QPen(h_pen, lw * 0.85))
        p.setBrush(QBrush(c_fill))
        p.drawPath(ws)

        # Glass panels (port + stbd)
        for sign in (-1, 1):
            pg = QPainterPath()
            pg.moveTo(sign * r*0.22, -r*0.34)
            pg.lineTo(sign * r*0.16, -r*0.54)
            pg.lineTo(sign * r*0.02, -r*0.60)
            pg.lineTo(sign * r*0.02, -r*0.34)
            pg.closeSubpath()
            p.setPen(QPen(color.darker(122), max(1, r*0.016)))
            p.setBrush(QBrush(win_col.lighter(145)))
            p.drawPath(pg)

        # ── MAST ───────────────────────────────────────────────────
        p.setPen(QPen(color.darker(128), max(1.5, r*0.030)))
        p.drawLine(QPointF(0, -r*0.64), QPointF(0, -r*0.92))
        # Radar dome
        p.setPen(QPen(h_pen, max(1, r*0.015)))
        p.setBrush(QBrush(color.darker(160)))
        p.drawEllipse(QPointF(0, -r*0.90), r*0.054, r*0.038)

        # ── NAV LIGHTS ─────────────────────────────────────────────
        p.setPen(Qt.NoPen)
        p.setBrush(QBrush(QColor(220, 40, 40, 240)))
        p.drawEllipse(QPointF(-r*0.90, -r*0.14), r*0.036, r*0.036)
        p.setBrush(QBrush(QColor(40, 205, 80, 240)))
        p.drawEllipse(QPointF( r*0.90, -r*0.14), r*0.036, r*0.036)

        # Keel stem
        p.setPen(QPen(color.darker(120), max(1.0, r*0.030)))
        p.drawLine(QPointF(0, r*0.50), QPointF(0, r*0.12))

    # ── CARGO SHIP ────────────────────────────────────────────────────────────

    def _boat_side_cargo(self, p, r, color):
        """Bulk carrier starboard profile — bow right, bridge + funnel at stern (left).
        High freeboard, 4 prominent goalpost cranes, bulbous bow."""
        lw      = max(1.0, r * 0.022)
        h_fill  = color.darker(152)
        h_pen   = color.darker(190)
        s_fill  = color.darker(160)
        crane_c = color.darker(122)

        DK  = -r * 0.14   # deck rail (above center = negative y)
        WL  =  r * 0.24   # waterline
        KL  =  r * 0.44   # keel
        DT  = DK - r*0.10  # deck top surface

        # ── HULL — very elongated, high freeboard ──────────────────
        hull = QPainterPath()
        hull.moveTo(-r*0.93, DK)
        hull.lineTo(-r*0.93, KL)                         # stern vertical
        hull.lineTo( r*0.74, KL)                         # flat keel
        hull.quadTo( r*0.94, KL,  r*0.94, WL)           # bow keel curve
        hull.lineTo( r*0.94, DT - r*0.06)                # bow stem
        hull.quadTo( r*0.86, DT - r*0.10, r*0.64, DT - r*0.10)
        hull.lineTo(-r*0.86, DT - r*0.10)                # flat main deck
        hull.lineTo(-r*0.93, DK)
        hull.closeSubpath()
        p.setPen(QPen(h_pen, lw))
        p.setBrush(QBrush(h_fill))
        p.drawPath(hull)

        # Bulbous bow
        p.setPen(QPen(h_pen, lw * 0.70))
        p.setBrush(QBrush(h_fill.darker(114)))
        p.drawEllipse(QPointF(r*0.96, WL + r*0.04), r*0.036, r*0.066)

        # Boot stripe — bold red antifouling
        p.setPen(QPen(QColor(148, 12, 12, 245), max(2.5, r * 0.042)))
        p.drawLine(QPointF(-r*0.93, WL), QPointF(r*0.93, WL))

        # ── BRIDGE CASTLE at STERN — tall, prominent ───────────────
        # Level 1 — accommodation block (widest)
        p.setPen(QPen(h_pen, lw * 0.84))
        p.setBrush(QBrush(s_fill))
        p.drawRect(QRectF(-r*0.93, DT - r*0.52, r*0.44, r*0.42))
        # Level 2 — bridge deck
        p.setBrush(QBrush(s_fill.darker(110)))
        p.drawRect(QRectF(-r*0.91, DT - r*0.68, r*0.36, r*0.16))
        # Level 3 — wheelhouse
        p.setBrush(QBrush(s_fill.darker(122)))
        p.drawRect(QRectF(-r*0.88, DT - r*0.82, r*0.26, r*0.14))
        # Bridge windows row
        p.setPen(QPen(color.darker(122), max(1, r*0.015)))
        p.setBrush(QBrush(QColor(28, 48, 95, 230)))
        for wx in (-r*0.84, -r*0.74, -r*0.64):
            p.drawRect(QRectF(wx, DT - r*0.79, r*0.08, r*0.10))

        # Funnel — tall, slim, forward of bridge
        p.setPen(QPen(h_pen, lw * 0.78))
        p.setBrush(QBrush(h_fill.darker(124)))
        p.drawRect(QRectF(-r*0.60, DT - r*0.80, r*0.12, r*0.70))
        p.setBrush(QBrush(h_fill.darker(132)))
        p.drawRect(QRectF(-r*0.62, DT - r*0.88, r*0.16, r*0.10))  # cap

        # ── GOALPOST CRANES — 4 prominent H-frames ─────────────────
        ct = DT - r * 0.54   # crossbeam height
        hw = r * 0.058

        for gx in (-r*0.15, r*0.18, r*0.50, r*0.80):
            lp, rp = gx - hw, gx + hw
            # Vertical legs
            p.setPen(QPen(crane_c, max(2.0, r * 0.034)))
            p.drawLine(QPointF(lp, DT), QPointF(lp, ct))
            p.drawLine(QPointF(rp, DT), QPointF(rp, ct))
            # Crossbeam
            p.setPen(QPen(crane_c, max(1.5, r * 0.025)))
            p.drawLine(QPointF(lp - r*0.04, ct), QPointF(rp + r*0.04, ct))
            # Derrick booms angled outward
            p.setPen(QPen(crane_c, max(1.0, r * 0.018)))
            p.drawLine(QPointF(lp, ct + r*0.10),
                       QPointF(lp - r*0.20, ct - r*0.18))
            p.drawLine(QPointF(rp, ct + r*0.10),
                       QPointF(rp + r*0.20, ct - r*0.18))

        # ── CARGO HATCH COAMINGS — 4 hatches ──────────────────────
        p.setPen(QPen(h_pen, max(0.8, r * 0.015)))
        p.setBrush(QBrush(h_fill.lighter(118)))
        for hx in (-r*0.12, r*0.20, r*0.52, r*0.80):
            p.drawRoundedRect(QRectF(hx - r*0.12, DT + r*0.01, r*0.22, r*0.10),
                              r*0.012, r*0.012)

        # Nav lights
        p.setPen(Qt.NoPen)
        p.setBrush(QBrush(QColor(220, 40, 40, 232)))
        p.drawEllipse(QPointF(-r*0.91, DT - r*0.08), r*0.028, r*0.028)
        p.setBrush(QBrush(QColor(40, 205, 80, 232)))
        p.drawEllipse(QPointF( r*0.90, DT - r*0.08), r*0.028, r*0.028)

    def _boat_front_cargo(self, p, r, color):
        """Bulk carrier bow-on — wide boxy hull, full flare, tall stacked bridge."""
        lw     = max(1.0, r * 0.022)
        h_fill = color.darker(152)
        h_pen  = color.darker(190)
        s_fill = color.darker(160)
        DK  = -r * 0.12   # deck
        WL  =  r * 0.10   # waterline
        KL  =  r * 0.56   # keel
        HW  =  r * 0.90   # hull half-width — bulk carriers are WIDE

        # ── HULL below waterline — less V, more full-form ──────────
        hull_v = QPainterPath()
        hull_v.moveTo( 0,       KL)
        hull_v.lineTo(-r*0.36,  WL + r*0.10)
        hull_v.lineTo( r*0.36,  WL + r*0.10)
        hull_v.closeSubpath()
        p.setPen(Qt.NoPen)
        p.setBrush(QBrush(h_fill.darker(120)))
        p.drawPath(hull_v)

        # ── HULL TOPSIDES — wide, strong flare ─────────────────────
        hull = QPainterPath()
        hull.moveTo(-r*0.36,  WL + r*0.10)
        hull.quadTo(-r*0.70,  WL + r*0.02, -HW, DK + r*0.08)
        hull.lineTo(-HW, DK)
        hull.lineTo( HW, DK)
        hull.lineTo( HW, DK + r*0.08)
        hull.quadTo( r*0.70,  WL + r*0.02,  r*0.36,  WL + r*0.10)
        hull.closeSubpath()
        p.setPen(QPen(h_pen, lw))
        p.setBrush(QBrush(h_fill))
        p.drawPath(hull)

        # Boot stripe — bold red
        p.setPen(QPen(QColor(148, 12, 12, 245), max(2.5, r * 0.042)))
        p.drawLine(QPointF(-HW + r*0.06, WL), QPointF(HW - r*0.06, WL))

        # ── STACKED SUPERSTRUCTURE — 3 levels ──────────────────────
        for bw, bt, bh in [
            (r*0.56, DK - r*0.30, r*0.30),   # accommodation (widest)
            (r*0.42, DK - r*0.52, r*0.22),   # bridge deck
            (r*0.30, DK - r*0.70, r*0.18),   # wheelhouse
        ]:
            p.setPen(QPen(h_pen, lw * 0.82))
            p.setBrush(QBrush(s_fill))
            p.drawRect(QRectF(-bw, bt, bw * 2, bh))

        # Bridge windows — prominent row
        p.setPen(QPen(color.darker(122), max(1, r * 0.016)))
        p.setBrush(QBrush(QColor(28, 48, 95, 232)))
        win_y = DK - r*0.67
        for wx in (-r*0.24, -r*0.12, 0, r*0.12, r*0.24):
            p.drawRect(QRectF(wx - r*0.045, win_y, r*0.088, r*0.12))

        # Funnel top (visible above wheelhouse)
        p.setPen(QPen(h_pen, lw * 0.7))
        p.setBrush(QBrush(h_fill.darker(124)))
        p.drawRect(QRectF(-r*0.10, DK - r*0.88, r*0.20, r*0.18))

        # ── MAST + YARDARM + RADAR ─────────────────────────────────
        p.setPen(QPen(color.darker(128), max(1.5, r * 0.026)))
        p.drawLine(QPointF(0, DK - r*0.70), QPointF(0, DK - r*0.96))
        p.setPen(QPen(color.darker(132), max(1.0, r * 0.018)))
        p.drawLine(QPointF(-r*0.22, DK - r*0.88), QPointF(r*0.22, DK - r*0.88))
        p.setPen(QPen(h_pen, max(1, r * 0.014)))
        p.setBrush(QBrush(color.darker(164)))
        p.drawEllipse(QPointF(0, DK - r*0.94), r*0.046, r*0.032)

        # ── NAV LIGHTS ─────────────────────────────────────────────
        p.setPen(Qt.NoPen)
        p.setBrush(QBrush(QColor(220, 40, 40, 240)))
        p.drawEllipse(QPointF(-HW + r*0.02, DK + r*0.02), r*0.036, r*0.036)
        p.setBrush(QBrush(QColor(40, 205, 80, 240)))
        p.drawEllipse(QPointF( HW - r*0.02, DK + r*0.02), r*0.036, r*0.036)

        # Keel stem
        p.setPen(QPen(color.darker(120), max(1.0, r * 0.026)))
        p.drawLine(QPointF(0, KL), QPointF(0, WL + r*0.08))

    def _boat_top_cargo(self, p, r, color):
        """Bulk carrier plan view — bow at top, WIDE oval (bulk carriers are wide!),
        bridge castle at stern, 4 cargo holds, 2 goalpost crane pairs."""
        lw     = max(1.0, r * 0.022)
        h_fill = color.darker(152)
        h_pen  = color.darker(190)
        s_fill = color.darker(160)
        HW = r * 0.46   # hull half-width — bulk carriers have ~3:1 L/B ratio

        # ── HULL — wide oval with raked bow ────────────────────────
        hull = QPainterPath()
        hull.moveTo( 0,    -r*0.94)                          # bow tip
        hull.cubicTo(-r*0.20, -r*0.88, -HW, -r*0.70, -HW, -r*0.30)
        hull.lineTo(-HW,  r*0.50)                            # port flat side
        hull.quadTo(-HW,  r*0.76,  0,    r*0.86)            # stern port
        hull.quadTo( HW,  r*0.76,  HW,   r*0.50)            # stern stbd
        hull.lineTo( HW, -r*0.30)                            # stbd flat side
        hull.cubicTo( HW, -r*0.70, r*0.20, -r*0.88, 0, -r*0.94)
        hull.closeSubpath()
        p.setPen(QPen(h_pen, lw))
        p.setBrush(QBrush(h_fill))
        p.drawPath(hull)

        # ── BRIDGE CASTLE at STERN (bottom) ────────────────────────
        p.setPen(QPen(h_pen, lw * 0.82))
        p.setBrush(QBrush(s_fill))
        p.drawRoundedRect(QRectF(-r*0.32, r*0.52, r*0.64, r*0.26),
                          r*0.05, r*0.05)
        # Funnel — circle on superstructure
        p.setPen(QPen(h_pen, lw * 0.70))
        p.setBrush(QBrush(h_fill.darker(122)))
        p.drawEllipse(QPointF(0, r*0.70), r*0.086, r*0.072)

        # ── CARGO HOLDS — 4 wide hatches ───────────────────────────
        p.setPen(QPen(h_pen, max(0.9, r * 0.016)))
        p.setBrush(QBrush(h_fill.lighter(116)))
        for hy in (-r*0.72, -r*0.36, r*0.00, r*0.36):
            p.drawRoundedRect(QRectF(-r*0.38, hy, r*0.76, r*0.28),
                              r*0.04, r*0.04)

        # ── GOALPOST CRANE PAIRS — 2 sets of double H-frames ───────
        crane_c = color.darker(126)
        for cy_c in (-r*0.56, r*0.14):
            # Two athwartship beams (top and bottom chord of goalpost)
            p.setPen(QPen(crane_c, max(2.5, r * 0.044)))
            p.drawLine(QPointF(-r*0.38, cy_c - r*0.07),
                       QPointF( r*0.38, cy_c - r*0.07))
            p.drawLine(QPointF(-r*0.38, cy_c + r*0.07),
                       QPointF( r*0.38, cy_c + r*0.07))
            # Centerline spine
            p.setPen(QPen(crane_c, max(1.2, r * 0.018)))
            p.drawLine(QPointF(0, cy_c - r*0.10), QPointF(0, cy_c + r*0.10))

        # ── CENTERLINE dashed ───────────────────────────────────────
        p.setPen(QPen(color.darker(148), max(0.8, r * 0.016), Qt.DashLine))
        p.drawLine(QPointF(0, -r*0.88), QPointF(0, r*0.82))

        # ── BOW DIRECTION ARROW ─────────────────────────────────────
        arrow = QPainterPath()
        arrow.moveTo( 0,      -r*0.94)
        arrow.lineTo(-r*0.09, -r*0.78)
        arrow.lineTo( r*0.09, -r*0.78)
        arrow.closeSubpath()
        p.setBrush(QBrush(color))
        p.setPen(Qt.NoPen)
        p.drawPath(arrow)

        # ── NAV LIGHTS ─────────────────────────────────────────────
        p.setPen(Qt.NoPen)
        p.setBrush(QBrush(QColor(220, 40, 40, 240)))
        p.drawEllipse(QPointF(-HW + r*0.04, -r*0.48), r*0.040, r*0.040)
        p.setBrush(QBrush(QColor(40, 205, 80, 240)))
        p.drawEllipse(QPointF( HW - r*0.04, -r*0.48), r*0.040, r*0.040)

    def _boat_top(self, p, r, color):
        """Modern superyacht plan view — bow at top, sleek teardrop hull."""
        lw      = max(1.0, r * 0.025)
        h_fill  = color.darker(148)
        h_pen   = color.darker(185)
        c_fill  = color.darker(162)
        dk_fill = color.darker(155)

        # ── HULL — sharp bow, wide transom ─────────────────────────
        hull = QPainterPath()
        hull.moveTo( 0,       -r*0.94)
        hull.cubicTo(-r*0.20, -r*0.86, -r*0.38, -r*0.50, -r*0.38, -r*0.08)
        hull.cubicTo(-r*0.38,  r*0.22, -r*0.32,  r*0.50, -r*0.22,  r*0.64)
        hull.lineTo(-r*0.22,  r*0.76)
        hull.lineTo( r*0.22,  r*0.76)
        hull.lineTo( r*0.22,  r*0.64)
        hull.cubicTo( r*0.32,  r*0.50,  r*0.38,  r*0.22,  r*0.38, -r*0.08)
        hull.cubicTo( r*0.38, -r*0.50,  r*0.20, -r*0.86,  0,      -r*0.94)
        hull.closeSubpath()
        p.setPen(QPen(h_pen, lw))
        p.setBrush(QBrush(h_fill))
        p.drawPath(hull)

        # ── LONG SUPERSTRUCTURE ────────────────────────────────────
        p.setPen(QPen(h_pen, lw * 0.85))
        p.setBrush(QBrush(c_fill))
        p.drawRoundedRect(QRectF(-r*0.22, -r*0.34, r*0.44, r*0.64),
                          r*0.06, r*0.06)

        # ── BRIDGE (forward section of superstructure) ─────────────
        p.setBrush(QBrush(c_fill.darker(112)))
        p.drawRoundedRect(QRectF(-r*0.15, -r*0.30, r*0.30, r*0.22),
                          r*0.05, r*0.05)

        # ── AFT DECK (open) ────────────────────────────────────────
        p.setBrush(QBrush(dk_fill))
        p.drawRoundedRect(QRectF(-r*0.18, r*0.36, r*0.36, r*0.26),
                          r*0.04, r*0.04)

        # ── SWIM PLATFORM ──────────────────────────────────────────
        p.setBrush(QBrush(h_fill.darker(110)))
        p.drawRoundedRect(QRectF(-r*0.16, r*0.64, r*0.32, r*0.12),
                          r*0.03, r*0.03)

        # ── FOREDECK HATCH ─────────────────────────────────────────
        p.setPen(QPen(h_pen, lw * 0.80))
        p.setBrush(QBrush(h_fill.darker(108)))
        p.drawRoundedRect(QRectF(-r*0.06, -r*0.60, r*0.12, r*0.10),
                          r*0.02, r*0.02)
        p.drawRoundedRect(QRectF(-r*0.06, -r*0.46, r*0.12, r*0.10),
                          r*0.02, r*0.02)

        # ── CENTERLINE ─────────────────────────────────────────────
        p.setPen(QPen(color.darker(148), max(0.8, r*0.016), Qt.DashLine))
        p.drawLine(QPointF(0, -r*0.88), QPointF(0, r*0.70))

        # ── BOW DIRECTION ARROW ─────────────────────────────────────
        arrow = QPainterPath()
        arrow.moveTo( 0,      -r*0.94)
        arrow.lineTo(-r*0.08, -r*0.78)
        arrow.lineTo( r*0.08, -r*0.78)
        arrow.closeSubpath()
        p.setBrush(QBrush(color))
        p.setPen(Qt.NoPen)
        p.drawPath(arrow)

        # ── NAV LIGHTS ─────────────────────────────────────────────
        p.setBrush(QBrush(QColor(220, 40, 40, 240)))
        p.drawEllipse(QPointF(-r*0.36, -r*0.22), r*0.038, r*0.038)
        p.setBrush(QBrush(QColor(40, 205, 80, 240)))
        p.drawEllipse(QPointF( r*0.36, -r*0.22), r*0.038, r*0.038)
