import { useState } from "react";

// ---------------------------------------------------------------------------
// Data — full Vesper Firmware API Reference v2
// ---------------------------------------------------------------------------

const TRANSPORTS = [
  { transport: "MQTT", address: "vesper/{device_id}/control", direction: "Inbound", notes: "Commands in. Responses go to vesper/{device_id}/data" },
  { transport: "MQTT", address: "vesper/{device_id}/data", direction: "Outbound", notes: "Responses + events" },
  { transport: "MQTT", address: "vesper/{device_id}/status/heartbeat", direction: "Outbound, retained", notes: "Heartbeat every 30 s" },
  { transport: "MQTT", address: "vesper/{device_id}/status/alerts", direction: "Outbound, QoS 1", notes: "Subsystem state changes (WARNING / CRITICAL / FAILED / CLEARED). Published on transition only." },
  { transport: "MQTT", address: "vesper/{device_id}/status/info", direction: "Outbound, QoS 0", notes: "Significant device events (playback start/stop, etc.)." },
  { transport: "WebSocket", address: "ws://{device_ip}/ws", direction: "Bidirectional", notes: "Requires identify on connect" },
  { transport: "HTTP", address: "http://{device_ip}/...", direction: "REST", notes: "Web console endpoints" },
  { transport: "UART", address: "Hardware serial", direction: "Bidirectional", notes: "Restricted — whitelist only" },
  { transport: "UDP", address: "Port 32101", direction: "Discovery", notes: "Passive — device announces itself" },
];

const UART_WHITELIST = ["ping", "playback", "clock.pause", "clock.resume", "system.get_time"];

const TRANSPORT_COLORS = {
  MQTT: { bg: "var(--badge-blue-bg)", color: "var(--badge-blue-text)" },
  WebSocket: { bg: "#2d1b4e", color: "#b794f4" },
  HTTP: { bg: "#1a2e0a", color: "var(--success-text)" },
  UART: { bg: "#2a1a0a", color: "#fbd38d" },
  UDP: { bg: "#1a2d2e", color: "#76e4f7" },
  All: { bg: "var(--bg-primary)", color: "var(--text-secondary)" },
};

const NAMESPACES = [
  {
    id: "root",
    label: "Root",
    description: "Top-level commands — no namespace prefix.",
    commands: [
      {
        cmd: "ping",
        handler: "SystemHandler",
        transports: ["All"],
        description: "Connectivity check. No contents required.",
        contents: null,
        returns: '{ "status": "SUCCESS", "type": "pong" }',
        example: '{ "v": 2, "cmd": "ping" }',
        warning: null,
      },
      {
        cmd: "identify",
        handler: "SystemHandler",
        transports: ["WebSocket"],
        description: "Register client type with the device. Must be sent immediately after connecting on WebSocket or targeted responses will not be received.",
        contents: [
          { field: "device_type", type: "string", required: true, notes: '"master" (app/console) or "secondary" (slave board)' },
        ],
        returns: null,
        example: '{ "v": 2, "cmd": "identify", "contents": { "device_type": "master" } }',
        warning: null,
      },
      {
        cmd: "playback",
        handler: "PlaybackHandler",
        transports: ["All"],
        description: 'Control melody playback. The action field is always required.',
        contents: [
          { field: "action", type: "string", required: true, notes: '"play" | "stop" | "pause" | "unpause"' },
          { field: "melody_uid", type: "string", required: false, notes: "Required when action is play" },
        ],
        returns: null,
        example: '{ "v": 2, "cmd": "playback", "contents": { "action": "play", "melody_uid": "ABC123" } }\n{ "v": 2, "cmd": "playback", "contents": { "action": "stop" } }',
        warning: null,
      },
    ],
  },
  {
    id: "relay",
    label: "relay",
    description: "Bell relay channel configuration and testing. Handler: RelayHandler.",
    commands: [
      {
        cmd: "relay.set_durations",
        handler: "RelayHandler",
        transports: ["All"],
        description: "Set strike duration (ms) for one or more bell channels. Partial updates accepted — omitted channels are unchanged.",
        contents: [
          { field: "bells", type: "object", required: true, notes: 'Map of channel index → duration ms. e.g. { "0": 95, "2": 110 }. At least one entry required.' },
        ],
        returns: null,
        example: '{\n  "v": 2,\n  "cmd": "relay.set_durations",\n  "contents": { "bells": { "0": 95, "1": 100, "2": 110 } }\n}',
        warning: null,
      },
      {
        cmd: "relay.set_outputs",
        handler: "RelayHandler",
        transports: ["All"],
        description: "Map bell channels to physical relay outputs. Partial updates accepted.",
        contents: [
          { field: "bells", type: "object", required: true, notes: 'Map of channel index → relay output index. e.g. { "0": 2, "1": 3 }' },
        ],
        returns: null,
        example: '{\n  "v": 2,\n  "cmd": "relay.set_outputs",\n  "contents": { "bells": { "0": 2, "1": 3, "2": 4 } }\n}',
        warning: null,
      },
      {
        cmd: "relay.get_config",
        handler: "RelayHandler",
        transports: ["All"],
        description: "Read current bell durations and relay output assignments.",
        contents: null,
        returns: '{ "durations": { "0": 95, ... }, "outputs": { "0": 2, ... } }',
        example: '{ "v": 2, "cmd": "relay.get_config" }',
        warning: null,
      },
      {
        cmd: "relay.test_output",
        handler: "RelayHandler",
        transports: ["All"],
        description: "Fire a specific relay for a caller-specified duration. Safety-gated: Player must be stopped.",
        contents: [
          { field: "output", type: "int", required: true, notes: "Physical relay output index" },
          { field: "duration_ms", type: "int", required: true, notes: "Duration in ms. No defaults. Typical range: 85–140 ms" },
        ],
        returns: null,
        example: '{\n  "v": 2,\n  "cmd": "relay.test_output",\n  "contents": { "output": 2, "duration_ms": 95 }\n}',
        warning: null,
      },
    ],
  },
  {
    id: "clock",
    label: "clock",
    description: "Clock strike configuration, RTC time, face position, timezone, and silence periods. Handler: ClockHandler.",
    commands: [
      {
        cmd: "clock.set_outputs",
        handler: "ClockHandler",
        transports: ["All"],
        description: "Set which relay outputs the clock strikes use. Partial updates accepted.",
        contents: [
          { field: "c1", type: "int", required: false, notes: "Relay output for the first clock channel" },
          { field: "c2", type: "int", required: false, notes: "Relay output for the second clock channel. At least one of c1/c2 required." },
        ],
        returns: null,
        example: '{ "v": 2, "cmd": "clock.set_outputs", "contents": { "c1": 4, "c2": 5 } }',
        warning: null,
      },
      {
        cmd: "clock.set_timings",
        handler: "ClockHandler",
        transports: ["All"],
        description: "Set clock strike timing configuration. Partial updates accepted.",
        contents: null,
        returns: null,
        example: '{ "v": 2, "cmd": "clock.set_timings", "contents": { ... } }',
        warning: null,
      },
      {
        cmd: "clock.set_alerts",
        handler: "ClockHandler",
        transports: ["All"],
        description: "Configure hourly/quarter alert behavior. Partial updates accepted.",
        contents: null,
        returns: null,
        example: '{ "v": 2, "cmd": "clock.set_alerts", "contents": { ... } }',
        warning: null,
      },
      {
        cmd: "clock.set_backlight",
        handler: "ClockHandler",
        transports: ["All"],
        description: "Configure LCD backlight behavior. Partial updates accepted.",
        contents: null,
        returns: null,
        example: '{ "v": 2, "cmd": "clock.set_backlight", "contents": { ... } }',
        warning: null,
      },
      {
        cmd: "clock.set_silence",
        handler: "ClockHandler",
        transports: ["All"],
        description: "Configure silence period (quiet hours). Partial updates accepted.",
        contents: null,
        returns: null,
        example: '{ "v": 2, "cmd": "clock.set_silence", "contents": { ... } }',
        warning: null,
      },
      {
        cmd: "clock.set_time",
        handler: "ClockHandler",
        transports: ["All"],
        description: "Set the RTC time.",
        contents: [
          { field: "timestamp", type: "int", required: true, notes: "Unix epoch timestamp" },
          { field: "timezone_offset", type: "int", required: false, notes: "Offset in seconds (e.g. 7200 for UTC+2)" },
          { field: "dst_offset", type: "int", required: false, notes: "DST offset in seconds" },
        ],
        returns: null,
        example: '{\n  "v": 2,\n  "cmd": "clock.set_time",\n  "contents": { "timestamp": 1740000000, "timezone_offset": 7200 }\n}',
        warning: null,
      },
      {
        cmd: "clock.set_face",
        handler: "ClockHandler",
        transports: ["All"],
        description: "Set the physical analog clock face position.",
        contents: [
          { field: "hour", type: "int", required: true, notes: "Hour hand position (0–11)" },
          { field: "minute", type: "int", required: true, notes: "Minute hand position (0–59)" },
        ],
        returns: null,
        example: '{ "v": 2, "cmd": "clock.set_face", "contents": { "hour": 10, "minute": 10 } }',
        warning: null,
      },
      {
        cmd: "clock.set_timezone",
        handler: "ClockHandler",
        transports: ["All"],
        description: "Set timezone independently of RTC time.",
        contents: [
          { field: "gmt_offset_sec", type: "int", required: true, notes: "GMT offset in seconds (e.g. 7200 for UTC+2)" },
          { field: "dst_offset_sec", type: "int", required: false, notes: "DST offset in seconds" },
          { field: "timezone_name", type: "string", required: false, notes: 'IANA timezone name, e.g. "Europe/Athens"' },
        ],
        returns: null,
        example: '{\n  "v": 2,\n  "cmd": "clock.set_timezone",\n  "contents": { "gmt_offset_sec": 7200, "dst_offset_sec": 3600, "timezone_name": "Europe/Athens" }\n}',
        warning: null,
      },
      {
        cmd: "clock.get_timezone",
        handler: "ClockHandler",
        transports: ["All"],
        description: "Read current timezone settings.",
        contents: null,
        returns: '{ "gmt_offset_sec": 7200, "dst_offset_sec": 3600, "timezone_name": "..." }',
        example: '{ "v": 2, "cmd": "clock.get_timezone" }',
        warning: null,
      },
      {
        cmd: "clock.sync_ntp",
        handler: "ClockHandler",
        transports: ["All"],
        description: "Force an immediate NTP time sync.",
        contents: null,
        returns: null,
        example: '{ "v": 2, "cmd": "clock.sync_ntp" }',
        warning: null,
      },
      {
        cmd: "clock.enable",
        handler: "ClockHandler",
        transports: ["All"],
        description: "Enable clock strike output.",
        contents: null,
        returns: null,
        example: '{ "v": 2, "cmd": "clock.enable" }',
        warning: null,
      },
      {
        cmd: "clock.disable",
        handler: "ClockHandler",
        transports: ["All"],
        description: "Disable clock strike output.",
        contents: null,
        returns: null,
        example: '{ "v": 2, "cmd": "clock.disable" }',
        warning: null,
      },
      {
        cmd: "clock.pause",
        handler: "ClockHandler",
        transports: ["All"],
        description: "Pause clock updates.",
        contents: null,
        returns: null,
        example: '{ "v": 2, "cmd": "clock.pause" }',
        warning: null,
      },
      {
        cmd: "clock.resume",
        handler: "ClockHandler",
        transports: ["All"],
        description: "Resume clock updates.",
        contents: null,
        returns: null,
        example: '{ "v": 2, "cmd": "clock.resume" }',
        warning: null,
      },
      {
        cmd: "clock.get_face",
        handler: "ClockHandler",
        transports: ["All"],
        description: "Read current analog clock face position.",
        contents: null,
        returns: '{ "clock_hour", "clock_minute", "last_sync_time", "next_output_is_c1" }',
        example: '{ "v": 2, "cmd": "clock.get_face" }',
        warning: null,
      },
      {
        cmd: "clock.get_config",
        handler: "ClockHandler",
        transports: ["All"],
        description: "Read full clock configuration — outputs, timings, alerts, backlight, silence, enabled state.",
        contents: null,
        returns: null,
        example: '{ "v": 2, "cmd": "clock.get_config" }',
        warning: null,
      },
    ],
  },
  {
    id: "system",
    label: "system",
    description: "Device status, settings, health, and control. Handler: SystemHandler.",
    commands: [
      {
        cmd: "system.status",
        handler: "SystemHandler",
        transports: ["All"],
        description: "Get current device status: player state, strike counters, projected run time.",
        contents: null,
        returns: null,
        example: '{ "v": 2, "cmd": "system.status" }',
        warning: null,
      },
      {
        cmd: "system.get_time",
        handler: "SystemHandler",
        transports: ["All"],
        description: "Get current RTC time.",
        contents: null,
        returns: '{ "local_timestamp", "utc_timestamp", "year", "month", "day", "hour", "minute", "second", "rtc_available" }',
        example: '{ "v": 2, "cmd": "system.get_time" }',
        warning: null,
      },
      {
        cmd: "system.get_settings",
        handler: "SystemHandler",
        transports: ["All"],
        description: "Get full ConfigManager JSON dump (all saved settings).",
        contents: null,
        returns: null,
        example: '{ "v": 2, "cmd": "system.get_settings" }',
        warning: null,
      },
      {
        cmd: "system.get_device_info",
        handler: "SystemHandler",
        transports: ["All"],
        description: "Get device identity and runtime stats.",
        contents: null,
        returns: '{ "uid", "hw_type", "hw_version", "fw_version", "uptime_ms", "free_heap", "min_free_heap" }',
        example: '{ "v": 2, "cmd": "system.get_device_info" }',
        warning: null,
      },
      {
        cmd: "system.health",
        handler: "SystemHandler",
        transports: ["All"],
        description: "Get full HealthMonitor report — all subsystem states, warnings, and critical failures.",
        contents: null,
        returns: null,
        example: '{ "v": 2, "cmd": "system.health" }',
        warning: null,
      },
      {
        cmd: "system.factory_reset",
        handler: "SystemHandler",
        transports: ["All"],
        description: "Reset all settings to factory defaults.",
        contents: null,
        returns: null,
        example: '{ "v": 2, "cmd": "system.factory_reset" }',
        warning: "Non-reversible. All saved configuration is permanently wiped.",
      },
      {
        cmd: "system.restart",
        handler: "SystemHandler",
        transports: ["All"],
        description: "Reboot the device. Response is sent before reboot (2 s delay).",
        contents: null,
        returns: null,
        example: '{ "v": 2, "cmd": "system.restart" }',
        warning: null,
      },
    ],
  },
  {
    id: "firmware",
    label: "firmware",
    description: "OTA slot management — validate, commit, and roll back firmware. Handler: FirmwareHandler.",
    commands: [
      {
        cmd: "firmware.status",
        handler: "FirmwareHandler",
        transports: ["All"],
        description: "Get firmware validation state.",
        contents: null,
        returns: '{ "validation_state", "version", "boot_count", "can_commit", "can_rollback" }',
        example: '{ "v": 2, "cmd": "firmware.status" }',
        warning: null,
      },
      {
        cmd: "firmware.commit",
        handler: "FirmwareHandler",
        transports: ["All"],
        description: "Commit the current firmware as permanent (marks OTA slot as valid).",
        contents: null,
        returns: null,
        example: '{ "v": 2, "cmd": "firmware.commit" }',
        warning: null,
      },
      {
        cmd: "firmware.rollback",
        handler: "FirmwareHandler",
        transports: ["All"],
        description: "Roll back to the previous firmware. Device reboots.",
        contents: null,
        returns: null,
        example: '{ "v": 2, "cmd": "firmware.rollback" }',
        warning: "Device will reboot immediately after this command.",
      },
    ],
  },
  {
    id: "ota",
    label: "ota",
    description: "Over-the-air update management. Handler: FirmwareHandler.",
    commands: [
      {
        cmd: "ota.status",
        handler: "FirmwareHandler",
        transports: ["All"],
        description: "Get OTA update status.",
        contents: null,
        returns: '{ "current_version", "available_version", "channel", "update_available", "last_check", "progress" }',
        example: '{ "v": 2, "cmd": "ota.status" }',
        warning: null,
      },
      {
        cmd: "ota.check",
        handler: "FirmwareHandler",
        transports: ["All"],
        description: "Check for available updates.",
        contents: [
          { field: "channel", type: "string", required: false, notes: 'Update channel. Default: "stable"' },
        ],
        returns: null,
        example: '{ "v": 2, "cmd": "ota.check", "contents": { "channel": "beta" } }',
        warning: null,
      },
      {
        cmd: "ota.update",
        handler: "FirmwareHandler",
        transports: ["All"],
        description: "Trigger OTA update from VPS. Device may reboot after flashing.",
        contents: [
          { field: "channel", type: "string", required: false, notes: 'Update channel. Default: "stable"' },
        ],
        returns: null,
        example: '{ "v": 2, "cmd": "ota.update", "contents": { "channel": "stable" } }',
        warning: "Device may reboot after the update is applied.",
      },
      {
        cmd: "ota.custom",
        handler: "FirmwareHandler",
        transports: ["All"],
        description: "Flash firmware from a custom URL.",
        contents: [
          { field: "firmware_url", type: "string", required: true, notes: "Direct download URL for the firmware binary" },
          { field: "checksum", type: "string", required: false, notes: "Optional integrity checksum" },
          { field: "file_size", type: "int", required: false, notes: "Optional file size in bytes" },
          { field: "version", type: "string", required: false, notes: "Version label for display purposes" },
        ],
        returns: null,
        example: '{\n  "v": 2,\n  "cmd": "ota.custom",\n  "contents": {\n    "firmware_url": "http://example.com/firmware.bin",\n    "checksum": "abc123",\n    "version": "142"\n  }\n}',
        warning: "Device may reboot after the update is applied.",
      },
    ],
  },
  {
    id: "network",
    label: "network",
    description: "Network configuration and connection status. Handler: NetworkHandler.",
    commands: [
      {
        cmd: "network.info",
        handler: "NetworkHandler",
        transports: ["All"],
        description: "Get IP address, gateway, and DNS.",
        contents: null,
        returns: '{ "ip", "gateway", "dns" }',
        example: '{ "v": 2, "cmd": "network.info" }',
        warning: null,
      },
      {
        cmd: "network.status",
        handler: "NetworkHandler",
        transports: ["All"],
        description: "Get full connection state.",
        contents: null,
        returns: '{ "connected", "state", "type", "ip", "rssi", "ap_mode" }',
        example: '{ "v": 2, "cmd": "network.status" }',
        warning: null,
      },
      {
        cmd: "network.set_config",
        handler: "NetworkHandler",
        transports: ["All"],
        description: "Update network configuration. Partial updates accepted. Returns restart_required flag.",
        contents: [
          { field: "hostname", type: "string", required: false, notes: "Device hostname on the network" },
          { field: "useStaticIP", type: "bool", required: false, notes: "Enable static IP mode" },
          { field: "ip", type: "string", required: false, notes: "Static IP address. Required together with gateway + subnet when using static IP." },
          { field: "gateway", type: "string", required: false, notes: "Gateway address" },
          { field: "subnet", type: "string", required: false, notes: "Subnet mask" },
          { field: "dns1", type: "string", required: false, notes: "Primary DNS" },
          { field: "dns2", type: "string", required: false, notes: "Secondary DNS" },
        ],
        returns: '{ "restart_required": true/false }',
        example: '{\n  "v": 2,\n  "cmd": "network.set_config",\n  "contents": { "hostname": "vesper-lab", "useStaticIP": false }\n}',
        warning: null,
      },
    ],
  },
  {
    id: "files",
    label: "files",
    description: "Melody file management on the SD card and built-in firmware storage. Handler: FileHandler.",
    commands: [
      {
        cmd: "files.list",
        handler: "FileHandler",
        transports: ["All"],
        description: "List melody files on the SD card.",
        contents: null,
        returns: "Array of SD card melody file objects",
        example: '{ "v": 2, "cmd": "files.list" }',
        warning: null,
      },
      {
        cmd: "files.list_builtin",
        handler: "FileHandler",
        transports: ["All"],
        description: "List all built-in melodies compiled into the firmware.",
        contents: null,
        returns: '[{ "name": "...", "uid": "..." }, ...]',
        example: '{ "v": 2, "cmd": "files.list_builtin" }',
        warning: null,
      },
      {
        cmd: "files.download",
        handler: "FileHandler",
        transports: ["All"],
        description: "Download a melody from the server to the SD card.",
        contents: [
          { field: "melodys_uid", type: "string", required: true, notes: "UID of the melody to download" },
        ],
        returns: null,
        example: '{ "v": 2, "cmd": "files.download", "contents": { "melodys_uid": "ABC123" } }',
        warning: null,
      },
      {
        cmd: "files.delete",
        handler: "FileHandler",
        transports: ["All"],
        description: "Delete a melody file from the SD card.",
        contents: [
          { field: "name", type: "string", required: true, notes: 'Filename including extension, e.g. "westminster.mel"' },
        ],
        returns: null,
        example: '{ "v": 2, "cmd": "files.delete", "contents": { "name": "westminster.mel" } }',
        warning: null,
      },
    ],
  },
  {
    id: "log",
    label: "log",
    description: "Log verbosity control per output channel. Level 0 = off, 5 = verbose. Handler: LoggingHandler.",
    commands: [
      {
        cmd: "log.set_serial",
        handler: "LoggingHandler",
        transports: ["All"],
        description: "Set log verbosity for the UART serial output.",
        contents: [
          { field: "level", type: "int", required: true, notes: "0 = None, 1 = Error, 2 = Warning, 3 = Info, 4 = Debug, 5 = Verbose" },
        ],
        returns: null,
        example: '{ "v": 2, "cmd": "log.set_serial", "contents": { "level": 3 } }',
        warning: null,
      },
      {
        cmd: "log.set_sd",
        handler: "LoggingHandler",
        transports: ["All"],
        description: "Set log verbosity for SD card logging.",
        contents: [
          { field: "level", type: "int", required: true, notes: "0 = None, 1 = Error, 2 = Warning, 3 = Info, 4 = Debug, 5 = Verbose" },
        ],
        returns: null,
        example: '{ "v": 2, "cmd": "log.set_sd", "contents": { "level": 2 } }',
        warning: null,
      },
      {
        cmd: "log.set_mqtt",
        handler: "LoggingHandler",
        transports: ["All"],
        description: "Set log verbosity for MQTT log publishing.",
        contents: [
          { field: "level", type: "int", required: true, notes: "0 = None, 1 = Error, 2 = Warning, 3 = Info, 4 = Debug, 5 = Verbose" },
        ],
        returns: null,
        example: '{ "v": 2, "cmd": "log.set_mqtt", "contents": { "level": 1 } }',
        warning: null,
      },
    ],
  },
  {
    id: "mqtt",
    label: "mqtt",
    description: "MQTT connectivity control. Handler: MQTTHandler.",
    commands: [
      {
        cmd: "mqtt.enable",
        handler: "MQTTHandler",
        transports: ["All"],
        description: "Enable MQTT connectivity.",
        contents: null,
        returns: null,
        example: '{ "v": 2, "cmd": "mqtt.enable" }',
        warning: null,
      },
      {
        cmd: "mqtt.disable",
        handler: "MQTTHandler",
        transports: ["All"],
        description: "Disable MQTT connectivity.",
        contents: null,
        returns: null,
        example: '{ "v": 2, "cmd": "mqtt.disable" }',
        warning: null,
      },
    ],
  },
  {
    id: "telemetry",
    label: "telemetry",
    description: "Bell strike counters and thermal load monitoring. Handler: TelemetryHandler.",
    commands: [
      {
        cmd: "telemetry.get_strikes",
        handler: "TelemetryHandler",
        transports: ["All"],
        description: "Get strike counts per bell channel.",
        contents: null,
        returns: '{ "strikes": { "0": 1234, "1": 567, ... } }',
        example: '{ "v": 2, "cmd": "telemetry.get_strikes" }',
        warning: null,
      },
      {
        cmd: "telemetry.reset_strikes",
        handler: "TelemetryHandler",
        transports: ["All"],
        description: "Reset strike counters. Omit bell to reset all channels; include it to reset a single channel.",
        contents: [
          { field: "bell", type: "int", required: false, notes: "Channel index. If omitted, all channels are reset." },
        ],
        returns: null,
        example: '{ "v": 2, "cmd": "telemetry.reset_strikes" }\n{ "v": 2, "cmd": "telemetry.reset_strikes", "contents": { "bell": 2 } }',
        warning: null,
      },
      {
        cmd: "telemetry.get_loads",
        handler: "TelemetryHandler",
        transports: ["All"],
        description: "Get heat load per bell channel, cooling status, and overload flags.",
        contents: null,
        returns: '{ "loads": { "0": 42.5, ... }, "cooling_active": false, "overloaded": [2, 5] }',
        example: '{ "v": 2, "cmd": "telemetry.get_loads" }',
        warning: null,
      },
    ],
  },
];

const LEGACY_MAP = [
  { v1_cmd: "ping", v1_action: "—", v2: "ping" },
  { v1_cmd: "identify", v1_action: "—", v2: "identify" },
  { v1_cmd: "playback", v1_action: "—", v2: "playback" },
  { v1_cmd: "file_manager", v1_action: "list_melodies", v2: "files.list" },
  { v1_cmd: "file_manager", v1_action: "download_melody", v2: "files.download" },
  { v1_cmd: "file_manager", v1_action: "delete_melody", v2: "files.delete" },
  { v1_cmd: "relay_setup", v1_action: "set_timings", v2: "relay.set_durations" },
  { v1_cmd: "relay_setup", v1_action: "set_outputs", v2: "relay.set_outputs" },
  { v1_cmd: "clock_setup", v1_action: "set_outputs", v2: "clock.set_outputs" },
  { v1_cmd: "clock_setup", v1_action: "set_timings", v2: "clock.set_timings" },
  { v1_cmd: "clock_setup", v1_action: "set_alerts", v2: "clock.set_alerts" },
  { v1_cmd: "clock_setup", v1_action: "set_backlight", v2: "clock.set_backlight" },
  { v1_cmd: "clock_setup", v1_action: "set_silence", v2: "clock.set_silence" },
  { v1_cmd: "clock_setup", v1_action: "set_rtc_time", v2: "clock.set_time" },
  { v1_cmd: "clock_setup", v1_action: "set_physical_clock_time", v2: "clock.set_face" },
  { v1_cmd: "clock_setup", v1_action: "pause_clock_updates", v2: "clock.pause" },
  { v1_cmd: "clock_setup", v1_action: "resume_clock_updates", v2: "clock.resume" },
  { v1_cmd: "clock_setup", v1_action: 'set_enabled (enabled=true)', v2: "clock.enable" },
  { v1_cmd: "clock_setup", v1_action: 'set_enabled (enabled=false)', v2: "clock.disable" },
  { v1_cmd: "system_info", v1_action: "report_status", v2: "system.status" },
  { v1_cmd: "system_info", v1_action: "get_device_time", v2: "system.get_time" },
  { v1_cmd: "system_info", v1_action: "get_clock_time", v2: "clock.get_face" },
  { v1_cmd: "system_info", v1_action: "get_firmware_status", v2: "firmware.status" },
  { v1_cmd: "system_info", v1_action: "network_info", v2: "network.info" },
  { v1_cmd: "system_info", v1_action: "get_full_settings", v2: "system.get_settings" },
  { v1_cmd: "system_info", v1_action: "sync_time_to_lcd", v2: "system.get_time" },
  { v1_cmd: "system", v1_action: "status", v2: "system.status" },
  { v1_cmd: "system", v1_action: "reset_defaults", v2: "system.factory_reset" },
  { v1_cmd: "system", v1_action: "commit_firmware", v2: "firmware.commit" },
  { v1_cmd: "system", v1_action: "rollback_firmware", v2: "firmware.rollback" },
  { v1_cmd: "system", v1_action: "get_firmware_status", v2: "firmware.status" },
  { v1_cmd: "system", v1_action: "set_network_config", v2: "network.set_config" },
  { v1_cmd: "system", v1_action: "set_serial_log_level", v2: "log.set_serial" },
  { v1_cmd: "system", v1_action: "set_sd_log_level", v2: "log.set_sd" },
  { v1_cmd: "system", v1_action: "set_mqtt_log_level", v2: "log.set_mqtt" },
  { v1_cmd: "system", v1_action: 'set_mqtt_enabled (enabled=true)', v2: "mqtt.enable" },
  { v1_cmd: "system", v1_action: 'set_mqtt_enabled (enabled=false)', v2: "mqtt.disable" },
  { v1_cmd: "system", v1_action: "restart", v2: "system.restart" },
  { v1_cmd: "system", v1_action: "reboot", v2: "system.restart" },
  { v1_cmd: "system", v1_action: "force_update", v2: "ota.update" },
  { v1_cmd: "system", v1_action: "custom_update", v2: "ota.custom" },
];

// ---------------------------------------------------------------------------
// Sub-components
// ---------------------------------------------------------------------------

function TransportBadge({ name }) {
  const style = TRANSPORT_COLORS[name] || TRANSPORT_COLORS.All;
  return (
    <span
      className="px-2 py-0.5 text-xs rounded-full font-mono"
      style={{ backgroundColor: style.bg, color: style.color }}
    >
      {name}
    </span>
  );
}

function CodeBlock({ code }) {
  const [copied, setCopied] = useState(false);

  const handleCopy = () => {
    navigator.clipboard.writeText(code).then(() => {
      setCopied(true);
      setTimeout(() => setCopied(false), 1800);
    });
  };

  return (
    <div className="relative group">
      <pre
        className="text-xs p-3 rounded-md overflow-x-auto font-mono leading-relaxed"
        style={{ backgroundColor: "var(--bg-primary)", color: "#a3d977", border: "1px solid var(--border-secondary)" }}
      >
        {code}
      </pre>
      <button
        onClick={handleCopy}
        className="absolute top-2 right-2 px-2 py-1 text-xs rounded opacity-0 group-hover:opacity-100 transition-opacity"
        style={{
          backgroundColor: copied ? "var(--success-bg)" : "var(--bg-card-hover)",
          color: copied ? "var(--success-text)" : "var(--text-muted)",
          border: "1px solid var(--border-primary)",
        }}
      >
        {copied ? "Copied" : "Copy"}
      </button>
    </div>
  );
}

function CommandCard({ command }) {
  const [open, setOpen] = useState(false);

  return (
    <div
      className="rounded-lg border overflow-hidden"
      style={{ backgroundColor: "var(--bg-card)", borderColor: "var(--border-primary)" }}
    >
      {/* Header — always visible */}
      <button
        type="button"
        onClick={() => setOpen((v) => !v)}
        className="w-full flex items-center justify-between px-4 py-3 text-left hover:opacity-90 transition-opacity"
        style={{ backgroundColor: "var(--bg-card)" }}
      >
        <div className="flex items-center gap-3 min-w-0">
          <span
            className="font-mono text-sm font-semibold"
            style={{ color: "var(--accent)" }}
          >
            {command.cmd}
          </span>
          {command.warning && (
            <span
              className="px-2 py-0.5 text-xs rounded-full flex-shrink-0"
              style={{ backgroundColor: "#3b1a0a", color: "#f6ad55" }}
            >
              Warning
            </span>
          )}
          <span
            className="text-xs truncate hidden sm:block"
            style={{ color: "var(--text-muted)" }}
          >
            {command.description}
          </span>
        </div>
        <div className="flex items-center gap-2 flex-shrink-0 ml-3">
          {command.transports.map((t) => (
            <TransportBadge key={t} name={t} />
          ))}
          <svg
            className={`w-4 h-4 flex-shrink-0 transition-transform ml-1 ${open ? "rotate-90" : ""}`}
            fill="none"
            stroke="currentColor"
            viewBox="0 0 24 24"
            style={{ color: "var(--text-muted)" }}
          >
            <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
          </svg>
        </div>
      </button>

      {/* Expanded detail */}
      {open && (
        <div
          className="px-4 pb-4 pt-1 border-t"
          style={{ borderColor: "var(--border-secondary)" }}
        >
          {/* Description (full, visible on mobile too) */}
          <p className="text-sm mb-4" style={{ color: "var(--text-secondary)" }}>
            {command.description}
          </p>

          {/* Warning banner */}
          {command.warning && (
            <div
              className="flex items-start gap-2 rounded-md px-3 py-2 text-sm mb-4 border"
              style={{ backgroundColor: "#2a1a0a", borderColor: "#7c3a00", color: "#f6ad55" }}
            >
              <svg className="w-4 h-4 mt-0.5 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 9v2m0 4h.01M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z" />
              </svg>
              {command.warning}
            </div>
          )}

          <div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
            {/* Left column: meta + contents */}
            <div className="space-y-4">
              {/* Meta row */}
              <div className="flex flex-wrap gap-4 text-xs" style={{ color: "var(--text-muted)" }}>
                <div>
                  <span style={{ color: "var(--text-secondary)" }}>Handler</span>
                  <span
                    className="ml-2 font-mono"
                    style={{ color: "var(--badge-blue-text)" }}
                  >
                    {command.handler}
                  </span>
                </div>
                <div className="flex items-center gap-2">
                  <span style={{ color: "var(--text-secondary)" }}>Transports</span>
                  <span className="flex gap-1">
                    {command.transports.map((t) => (
                      <TransportBadge key={t} name={t} />
                    ))}
                  </span>
                </div>
              </div>

              {/* Contents table */}
              {command.contents ? (
                <div>
                  <p className="text-xs font-medium mb-2" style={{ color: "var(--text-secondary)" }}>
                    Contents
                  </p>
                  <div
                    className="rounded-md overflow-hidden border text-xs"
                    style={{ borderColor: "var(--border-secondary)" }}
                  >
                    <table className="w-full">
                      <thead>
                        <tr style={{ backgroundColor: "var(--bg-primary)" }}>
                          <th className="px-3 py-2 text-left font-medium" style={{ color: "var(--text-muted)", borderBottom: "1px solid var(--border-secondary)" }}>Field</th>
                          <th className="px-3 py-2 text-left font-medium" style={{ color: "var(--text-muted)", borderBottom: "1px solid var(--border-secondary)" }}>Type</th>
                          <th className="px-3 py-2 text-left font-medium" style={{ color: "var(--text-muted)", borderBottom: "1px solid var(--border-secondary)" }}>Req</th>
                          <th className="px-3 py-2 text-left font-medium" style={{ color: "var(--text-muted)", borderBottom: "1px solid var(--border-secondary)" }}>Notes</th>
                        </tr>
                      </thead>
                      <tbody>
                        {command.contents.map((field, i) => (
                          <tr
                            key={field.field}
                            style={{ borderTop: i > 0 ? "1px solid var(--border-secondary)" : "none" }}
                          >
                            <td className="px-3 py-2 font-mono" style={{ color: "var(--accent)" }}>{field.field}</td>
                            <td className="px-3 py-2 font-mono" style={{ color: "var(--badge-blue-text)" }}>{field.type}</td>
                            <td className="px-3 py-2">
                              {field.required ? (
                                <span style={{ color: "var(--danger-text)" }}>yes</span>
                              ) : (
                                <span style={{ color: "var(--text-muted)" }}>no</span>
                              )}
                            </td>
                            <td className="px-3 py-2" style={{ color: "var(--text-secondary)" }}>{field.notes}</td>
                          </tr>
                        ))}
                      </tbody>
                    </table>
                  </div>
                </div>
              ) : (
                <div className="text-xs" style={{ color: "var(--text-muted)" }}>
                  No contents required.
                </div>
              )}

              {/* Returns */}
              {command.returns && (
                <div>
                  <p className="text-xs font-medium mb-1" style={{ color: "var(--text-secondary)" }}>Returns</p>
                  <code
                    className="text-xs font-mono block p-2 rounded-md"
                    style={{ backgroundColor: "var(--bg-primary)", color: "var(--text-secondary)", border: "1px solid var(--border-secondary)" }}
                  >
                    {command.returns}
                  </code>
                </div>
              )}
            </div>

            {/* Right column: example */}
            <div>
              <p className="text-xs font-medium mb-2" style={{ color: "var(--text-secondary)" }}>
                Example
              </p>
              <CodeBlock code={command.example} />
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

function NamespaceSection({ ns, isActive, onToggle }) {
  return (
    <div id={`ns-${ns.id}`} className="mb-2">
      <button
        type="button"
        onClick={onToggle}
        className="w-full flex items-center justify-between px-4 py-3 rounded-lg text-left transition-colors"
        style={{
          backgroundColor: isActive ? "var(--bg-card-hover)" : "var(--bg-card)",
          border: "1px solid var(--border-primary)",
        }}
      >
        <div className="flex items-center gap-3">
          <span
            className="font-mono text-sm font-bold"
            style={{ color: isActive ? "var(--accent)" : "var(--text-heading)" }}
          >
            {ns.label === "root" ? "(root)" : ns.label}
          </span>
          <span className="text-xs" style={{ color: "var(--text-muted)" }}>
            {ns.commands.length} command{ns.commands.length !== 1 ? "s" : ""}
          </span>
        </div>
        <svg
          className={`w-4 h-4 transition-transform ${isActive ? "rotate-90" : ""}`}
          fill="none"
          stroke="currentColor"
          viewBox="0 0 24 24"
          style={{ color: "var(--text-muted)" }}
        >
          <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
        </svg>
      </button>

      {isActive && (
        <div className="mt-1 ml-2 pl-2 border-l space-y-1" style={{ borderColor: "var(--accent)" }}>
          <p className="text-xs pt-2 pb-1 px-1" style={{ color: "var(--text-muted)" }}>
            {ns.description}
          </p>
          {ns.commands.map((cmd) => (
            <CommandCard key={cmd.cmd} command={cmd} />
          ))}
        </div>
      )}
    </div>
  );
}

// ---------------------------------------------------------------------------
// Main Page
// ---------------------------------------------------------------------------

export default function ApiReferencePage() {
  const [activeNamespaces, setActiveNamespaces] = useState(new Set(["root"]));
  const [search, setSearch] = useState("");
  const [activeTab, setActiveTab] = useState("commands"); // "commands" | "transports" | "envelopes" | "events" | "legacy"

  const toggleNs = (id) => {
    setActiveNamespaces((prev) => {
      const next = new Set(prev);
      if (next.has(id)) next.delete(id);
      else next.add(id);
      return next;
    });
  };

  const expandAll = () => setActiveNamespaces(new Set(NAMESPACES.map((n) => n.id)));
  const collapseAll = () => setActiveNamespaces(new Set());

  // Filtered namespaces based on search
  const filteredNamespaces = search.trim()
    ? NAMESPACES.map((ns) => ({
        ...ns,
        commands: ns.commands.filter(
          (cmd) =>
            cmd.cmd.toLowerCase().includes(search.toLowerCase()) ||
            cmd.description.toLowerCase().includes(search.toLowerCase()) ||
            cmd.handler.toLowerCase().includes(search.toLowerCase())
        ),
      })).filter((ns) => ns.commands.length > 0)
    : NAMESPACES;

  const totalCommands = NAMESPACES.reduce((sum, ns) => sum + ns.commands.length, 0);

  const tabs = [
    { id: "commands", label: "Commands" },
    { id: "transports", label: "Transports" },
    { id: "envelopes", label: "Message Envelopes" },
    { id: "events", label: "MQTT Events" },
    { id: "legacy", label: "Legacy (v1)" },
  ];

  return (
    <div>
      {/* Page header */}
      <div className="mb-6">
        <div className="flex items-start justify-between gap-4 mb-1">
          <div>
            <h1 className="text-2xl font-bold" style={{ color: "var(--text-heading)" }}>
              API Reference
            </h1>
            <p className="text-sm mt-1" style={{ color: "var(--text-muted)" }}>
              Vesper command bus — v2 protocol &nbsp;&middot;&nbsp; {totalCommands} commands across {NAMESPACES.length} namespaces
            </p>
          </div>
          <div
            className="flex-shrink-0 px-3 py-1.5 rounded-md text-xs font-mono border"
            style={{ backgroundColor: "var(--bg-card)", borderColor: "var(--border-primary)", color: "var(--text-muted)" }}
          >
            v2 &nbsp;·&nbsp; 2026-03-01
          </div>
        </div>
      </div>

      {/* Tab bar */}
      <div
        className="flex gap-1 mb-6 p-1 rounded-lg w-fit"
        style={{ backgroundColor: "var(--bg-card)", border: "1px solid var(--border-primary)" }}
      >
        {tabs.map((tab) => (
          <button
            key={tab.id}
            type="button"
            onClick={() => setActiveTab(tab.id)}
            className="px-4 py-1.5 rounded-md text-sm transition-colors"
            style={{
              backgroundColor: activeTab === tab.id ? "var(--accent)" : "transparent",
              color: activeTab === tab.id ? "var(--bg-primary)" : "var(--text-secondary)",
              fontWeight: activeTab === tab.id ? "600" : "400",
            }}
          >
            {tab.label}
          </button>
        ))}
      </div>

      {/* ---- COMMANDS TAB ---- */}
      {activeTab === "commands" && (
        <div>
          {/* Search + controls */}
          <div className="flex flex-wrap items-center gap-3 mb-4">
            <input
              type="text"
              value={search}
              onChange={(e) => setSearch(e.target.value)}
              placeholder="Search commands..."
              className="px-3 py-2 rounded-md text-sm border w-64"
              style={{ backgroundColor: "var(--bg-card)", borderColor: "var(--border-primary)", color: "var(--text-primary)" }}
            />
            <button
              type="button"
              onClick={expandAll}
              className="px-3 py-2 text-sm rounded-md border transition-colors hover:opacity-80"
              style={{ backgroundColor: "var(--bg-card)", borderColor: "var(--border-primary)", color: "var(--text-secondary)" }}
            >
              Expand all
            </button>
            <button
              type="button"
              onClick={collapseAll}
              className="px-3 py-2 text-sm rounded-md border transition-colors hover:opacity-80"
              style={{ backgroundColor: "var(--bg-card)", borderColor: "var(--border-primary)", color: "var(--text-secondary)" }}
            >
              Collapse all
            </button>
            {search && (
              <span className="text-xs" style={{ color: "var(--text-muted)" }}>
                {filteredNamespaces.reduce((s, ns) => s + ns.commands.length, 0)} result(s)
              </span>
            )}
          </div>

          {filteredNamespaces.length === 0 ? (
            <div
              className="rounded-lg p-8 text-center text-sm border"
              style={{ backgroundColor: "var(--bg-card)", borderColor: "var(--border-primary)", color: "var(--text-muted)" }}
            >
              No commands match "{search}".
            </div>
          ) : (
            <div className="space-y-1">
              {filteredNamespaces.map((ns) => (
                <NamespaceSection
                  key={ns.id}
                  ns={ns}
                  isActive={activeNamespaces.has(ns.id) || search.trim() !== ""}
                  onToggle={() => toggleNs(ns.id)}
                />
              ))}
            </div>
          )}
        </div>
      )}

      {/* ---- TRANSPORTS TAB ---- */}
      {activeTab === "transports" && (
        <div className="space-y-6">
          <div
            className="rounded-lg border overflow-hidden"
            style={{ backgroundColor: "var(--bg-card)", borderColor: "var(--border-primary)" }}
          >
            <div className="px-4 py-3 border-b" style={{ borderColor: "var(--border-primary)" }}>
              <h2 className="text-sm font-semibold" style={{ color: "var(--text-heading)" }}>Available Transports</h2>
            </div>
            <div className="overflow-x-auto">
              <table className="w-full text-sm">
                <thead>
                  <tr style={{ backgroundColor: "var(--bg-primary)" }}>
                    {["Transport", "Address / Topic", "Direction", "Notes"].map((h) => (
                      <th
                        key={h}
                        className="px-4 py-3 text-left font-medium text-xs"
                        style={{ color: "var(--text-secondary)", borderBottom: "1px solid var(--border-primary)" }}
                      >
                        {h}
                      </th>
                    ))}
                  </tr>
                </thead>
                <tbody>
                  {TRANSPORTS.map((row, i) => (
                    <tr
                      key={i}
                      style={{ borderTop: i > 0 ? "1px solid var(--border-secondary)" : "none" }}
                    >
                      <td className="px-4 py-3">
                        <TransportBadge name={row.transport} />
                      </td>
                      <td className="px-4 py-3 font-mono text-xs" style={{ color: "var(--text-primary)" }}>{row.address}</td>
                      <td className="px-4 py-3 text-xs" style={{ color: "var(--text-secondary)" }}>{row.direction}</td>
                      <td className="px-4 py-3 text-xs" style={{ color: "var(--text-muted)" }}>{row.notes}</td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          </div>

          {/* UART whitelist */}
          <div
            className="rounded-lg border p-4"
            style={{ backgroundColor: "var(--bg-card)", borderColor: "var(--border-primary)" }}
          >
            <h2 className="text-sm font-semibold mb-3" style={{ color: "var(--text-heading)" }}>
              UART Whitelist
            </h2>
            <p className="text-xs mb-3" style={{ color: "var(--text-muted)" }}>
              Only the following commands are accepted over UART (LCD/button slave board). All others are silently dropped.
            </p>
            <div className="flex flex-wrap gap-2">
              {UART_WHITELIST.map((cmd) => (
                <code
                  key={cmd}
                  className="px-2 py-1 rounded text-xs font-mono"
                  style={{ backgroundColor: "var(--bg-primary)", color: "var(--accent)", border: "1px solid var(--border-secondary)" }}
                >
                  {cmd}
                </code>
              ))}
            </div>
          </div>

          {/* WebSocket identification */}
          <div
            className="rounded-lg border p-4"
            style={{ backgroundColor: "var(--bg-card)", borderColor: "var(--border-primary)" }}
          >
            <h2 className="text-sm font-semibold mb-3" style={{ color: "var(--text-heading)" }}>
              WebSocket — Client Identification
            </h2>
            <p className="text-xs mb-3" style={{ color: "var(--text-muted)" }}>
              WebSocket clients must send <code className="font-mono" style={{ color: "var(--accent)" }}>identify</code> immediately after connecting, or they will not receive targeted responses.
            </p>
            <CodeBlock code={'{ "v": 2, "cmd": "identify", "contents": { "device_type": "master" } }'} />
            <p className="text-xs mt-2" style={{ color: "var(--text-muted)" }}>
              <code className="font-mono" style={{ color: "var(--badge-blue-text)" }}>device_type</code>: &nbsp;
              <code className="font-mono">"master"</code> (app/console) or <code className="font-mono">"secondary"</code> (slave board)
            </p>
          </div>
        </div>
      )}

      {/* ---- ENVELOPES TAB ---- */}
      {activeTab === "envelopes" && (
        <div className="space-y-6">
          <div
            className="rounded-lg border p-4"
            style={{ backgroundColor: "var(--bg-card)", borderColor: "var(--border-primary)" }}
          >
            <h2 className="text-sm font-semibold mb-1" style={{ color: "var(--text-heading)" }}>Command Envelope</h2>
            <p className="text-xs mb-3" style={{ color: "var(--text-muted)" }}>
              Every command sent to Vesper uses this JSON structure.
            </p>
            <CodeBlock code={'{\n  "v": 2,\n  "cmd": "namespace.command",\n  "contents": { ... }\n}'} />
            <div
              className="mt-4 rounded-md overflow-hidden border text-xs"
              style={{ borderColor: "var(--border-secondary)" }}
            >
              <table className="w-full">
                <thead>
                  <tr style={{ backgroundColor: "var(--bg-primary)" }}>
                    {["Field", "Type", "Notes"].map((h) => (
                      <th
                        key={h}
                        className="px-3 py-2 text-left font-medium"
                        style={{ color: "var(--text-muted)", borderBottom: "1px solid var(--border-secondary)" }}
                      >
                        {h}
                      </th>
                    ))}
                  </tr>
                </thead>
                <tbody>
                  {[
                    { field: "v", type: "int", notes: 'Protocol version. 2 = current. Omit or set 1 for legacy (LegacyAdapter runs).' },
                    { field: "cmd", type: "string", notes: 'namespace.command format, e.g. "relay.set_durations".' },
                    { field: "contents", type: "object", notes: "Command payload. May be omitted if the command takes no fields." },
                  ].map((row, i) => (
                    <tr key={row.field} style={{ borderTop: i > 0 ? "1px solid var(--border-secondary)" : "none" }}>
                      <td className="px-3 py-2 font-mono" style={{ color: "var(--accent)" }}>{row.field}</td>
                      <td className="px-3 py-2 font-mono" style={{ color: "var(--badge-blue-text)" }}>{row.type}</td>
                      <td className="px-3 py-2" style={{ color: "var(--text-secondary)" }}>{row.notes}</td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          </div>

          <div
            className="rounded-lg border p-4"
            style={{ backgroundColor: "var(--bg-card)", borderColor: "var(--border-primary)" }}
          >
            <h2 className="text-sm font-semibold mb-1" style={{ color: "var(--text-heading)" }}>Response Envelope</h2>
            <p className="text-xs mb-3" style={{ color: "var(--text-muted)" }}>
              All responses from the device follow this format. On error, payload typically contains a <code className="font-mono" style={{ color: "var(--accent)" }}>message</code> string.
            </p>
            <CodeBlock code={'{\n  "status": "SUCCESS" | "ERROR",\n  "type": "command_name",\n  "payload": { ... }\n}'} />
            <div
              className="mt-4 rounded-md overflow-hidden border text-xs"
              style={{ borderColor: "var(--border-secondary)" }}
            >
              <table className="w-full">
                <thead>
                  <tr style={{ backgroundColor: "var(--bg-primary)" }}>
                    {["Field", "Values", "Notes"].map((h) => (
                      <th
                        key={h}
                        className="px-3 py-2 text-left font-medium"
                        style={{ color: "var(--text-muted)", borderBottom: "1px solid var(--border-secondary)" }}
                      >
                        {h}
                      </th>
                    ))}
                  </tr>
                </thead>
                <tbody>
                  {[
                    { field: "status", values: '"SUCCESS" | "ERROR"', notes: "Outcome of the command." },
                    { field: "type", values: "string", notes: "Command name that generated this response." },
                    { field: "payload", values: "object", notes: 'Command-specific data. On error: { "message": "..." }' },
                  ].map((row, i) => (
                    <tr key={row.field} style={{ borderTop: i > 0 ? "1px solid var(--border-secondary)" : "none" }}>
                      <td className="px-3 py-2 font-mono" style={{ color: "var(--accent)" }}>{row.field}</td>
                      <td className="px-3 py-2 font-mono" style={{ color: "var(--badge-blue-text)" }}>{row.values}</td>
                      <td className="px-3 py-2" style={{ color: "var(--text-secondary)" }}>{row.notes}</td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          </div>
        </div>
      )}

      {/* ---- MQTT EVENTS TAB ---- */}
      {activeTab === "events" && (
        <div className="space-y-6">
          <div
            className="rounded-lg border p-4"
            style={{ backgroundColor: "var(--bg-card)", borderColor: "var(--border-primary)" }}
          >
            <h2 className="text-sm font-semibold mb-1" style={{ color: "var(--text-heading)" }}>
              Unsolicited MQTT Events
            </h2>
            <p className="text-xs mb-4" style={{ color: "var(--text-muted)" }}>
              These messages are published by the device without a request.
            </p>
            <div className="overflow-x-auto">
              <table className="w-full text-xs">
                <thead>
                  <tr style={{ backgroundColor: "var(--bg-primary)" }}>
                    {["Topic", "When", "Format"].map((h) => (
                      <th
                        key={h}
                        className="px-3 py-2 text-left font-medium"
                        style={{ color: "var(--text-muted)", borderBottom: "1px solid var(--border-secondary)" }}
                      >
                        {h}
                      </th>
                    ))}
                  </tr>
                </thead>
                <tbody>
                  {[
                    {
                      topic: "vesper/{id}/status/heartbeat",
                      when: "Every 30 s, retained",
                      format: '{ "status": "INFO", "type": "heartbeat", "payload": { ... } }',
                    },
                    {
                      topic: "vesper/{id}/status/alerts",
                      when: "Subsystem state transition",
                      format: '{ "subsystem": "FileManager", "state": "WARNING", "msg": "..." }',
                    },
                    {
                      topic: "vesper/{id}/status/info",
                      when: "Significant device event",
                      format: '{ "type": "playback_started", "payload": { ... } }',
                    },
                    {
                      topic: "vesper/{id}/data",
                      when: "Any command response",
                      format: "Standard response envelope",
                    },
                  ].map((row, i) => (
                    <tr key={i} style={{ borderTop: i > 0 ? "1px solid var(--border-secondary)" : "none" }}>
                      <td className="px-3 py-2 font-mono" style={{ color: "var(--accent)" }}>{row.topic}</td>
                      <td className="px-3 py-2" style={{ color: "var(--text-secondary)" }}>{row.when}</td>
                      <td className="px-3 py-2 font-mono" style={{ color: "var(--text-muted)" }}>{row.format}</td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          </div>

          <div
            className="rounded-lg border p-4"
            style={{ backgroundColor: "var(--bg-card)", borderColor: "var(--border-primary)" }}
          >
            <h2 className="text-sm font-semibold mb-1" style={{ color: "var(--text-heading)" }}>Heartbeat Payload</h2>
            <p className="text-xs mb-3" style={{ color: "var(--text-muted)" }}>
              Published every 30 seconds with the retained flag. Subscribe to{" "}
              <code className="font-mono" style={{ color: "var(--accent)" }}>vesper/+/status/heartbeat</code>{" "}
              to discover all online devices on the broker.
            </p>
            <CodeBlock
              code={'{\n  "status": "INFO",\n  "type": "heartbeat",\n  "payload": {\n    "device_id": "PV-26B18-VS01R-X7KQA",\n    "firmware_version": "142",\n    "timestamp": "Uptime: 5h 23m 45s",\n    "ip_address": "10.0.0.3",\n    "gateway": "10.0.0.1",\n    "uptime_ms": 19425000\n  }\n}'}
            />
          </div>

          <div
            className="rounded-lg border p-4"
            style={{ backgroundColor: "var(--bg-card)", borderColor: "var(--border-primary)" }}
          >
            <h2 className="text-sm font-semibold mb-1" style={{ color: "var(--text-heading)" }}>Alerts Payload</h2>
            <p className="text-xs mb-3" style={{ color: "var(--text-muted)" }}>
              Published on{" "}
              <code className="font-mono" style={{ color: "var(--accent)" }}>vesper/+/status/alerts</code>{" "}
              only when a subsystem state changes (QoS 1, not retained). One message per transition.
              When a subsystem recovers, <code className="font-mono" style={{ color: "var(--accent)" }}>state</code> is <code className="font-mono" style={{ color: "var(--success-text)" }}>"CLEARED"</code> and <code className="font-mono" style={{ color: "var(--accent)" }}>msg</code> is omitted.
            </p>
            <CodeBlock
              code={'// Active alert\n{ "subsystem": "FileManager", "state": "WARNING", "msg": "SD mount failed" }\n\n// Recovery\n{ "subsystem": "FileManager", "state": "CLEARED" }'}
            />
          </div>

          <div
            className="rounded-lg border p-4"
            style={{ backgroundColor: "var(--bg-card)", borderColor: "var(--border-primary)" }}
          >
            <h2 className="text-sm font-semibold mb-1" style={{ color: "var(--text-heading)" }}>Info Payload</h2>
            <p className="text-xs mb-3" style={{ color: "var(--text-muted)" }}>
              Published on{" "}
              <code className="font-mono" style={{ color: "var(--accent)" }}>vesper/+/status/info</code>{" "}
              for significant device state changes (QoS 0, not retained). The <code className="font-mono" style={{ color: "var(--accent)" }}>type</code> field identifies the event; <code className="font-mono" style={{ color: "var(--accent)" }}>payload</code> carries event-specific data.
            </p>
            <CodeBlock
              code={'// Playback started\n{ "type": "playback_started", "payload": { "melody_uid": "ABC123" } }\n\n// Playback stopped\n{ "type": "playback_stopped", "payload": {} }'}
            />
          </div>
        </div>
      )}

      {/* ---- LEGACY TAB ---- */}
      {activeTab === "legacy" && (
        <div className="space-y-4">
          <div
            className="rounded-lg border p-4"
            style={{ backgroundColor: "var(--bg-card)", borderColor: "var(--border-primary)" }}
          >
            <h2 className="text-sm font-semibold mb-1" style={{ color: "var(--text-heading)" }}>Legacy Compatibility (v1)</h2>
            <p className="text-xs mb-1" style={{ color: "var(--text-muted)" }}>
              If a client sends <code className="font-mono" style={{ color: "var(--accent)" }}>"v": 1</code> (or omits <code className="font-mono" style={{ color: "var(--accent)" }}>v</code>), the <code className="font-mono" style={{ color: "var(--badge-blue-text)" }}>LegacyAdapter</code> automatically translates the old <code className="font-mono">cmd + action</code> pair to a v2 command before dispatch. No client-side code changes are required during migration.
            </p>
          </div>

          <div
            className="rounded-lg border overflow-hidden"
            style={{ backgroundColor: "var(--bg-card)", borderColor: "var(--border-primary)" }}
          >
            <div className="overflow-x-auto">
              <table className="w-full text-xs">
                <thead>
                  <tr style={{ backgroundColor: "var(--bg-primary)" }}>
                    {["v1 cmd", "v1 action", "v2 command"].map((h) => (
                      <th
                        key={h}
                        className="px-4 py-3 text-left font-medium"
                        style={{ color: "var(--text-secondary)", borderBottom: "1px solid var(--border-primary)" }}
                      >
                        {h}
                      </th>
                    ))}
                  </tr>
                </thead>
                <tbody>
                  {LEGACY_MAP.map((row, i) => (
                    <tr
                      key={i}
                      style={{ borderTop: i > 0 ? "1px solid var(--border-secondary)" : "none" }}
                    >
                      <td className="px-4 py-2 font-mono" style={{ color: "var(--text-secondary)" }}>{row.v1_cmd}</td>
                      <td className="px-4 py-2 font-mono" style={{ color: "var(--text-muted)" }}>{row.v1_action}</td>
                      <td className="px-4 py-2 font-mono" style={{ color: "var(--accent)" }}>{row.v2}</td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}
