#pragma once
// Tools › Compass. A standalone heading view: shows the device's course over
// ground (derived from GPS movement — there is no magnetometer) as a horizontal
// scrolling tape (N..E..S..W) under a fixed travel-direction marker, plus a
// large numeric degrees + cardinal readout. When standing still the heading is
// undefined, so it shows a hint to move.
//
// A linear tape (no trig) reads well in the short vertical space of the OLED,
// where a circular dial leaves only a few-pixel needle.
//
// Reuses UITask's COG ring (currentCourse) — works whether or not a trail is
// being recorded.

#include "../GeoUtils.h"
#include "icons.h"   // miniIconScale() — keeps the tape ticks/pointer legible on e-ink

class CompassScreen : public UIScreen {
  UITask* _task;

  bool gpsValid() const { int32_t lat, lon; return _task->currentLocation(lat, lon); }

  static const char* cardinalLetter(int deg) {
    switch (deg) { case 0: return "N"; case 90: return "E";
                   case 180: return "S"; case 270: return "W"; }
    return "";
  }

public:
  CompassScreen(UITask* task) : _task(task) {}
  void onShow() override {}

  int render(DisplayDriver& display) override {
    display.setTextSize(1);
    display.setColor(DisplayDriver::LIGHT);
    display.drawCenteredHeader("COMPASS");

    const int cx  = display.width() / 2;
    const int ch  = display.getLineHeight();
    const int cw  = display.getCharWidth();
    // Reserve a size-2 row at the bottom for the numeric readout.
    display.setTextSize(2);
    const int bigH = display.getLineHeight();
    display.setTextSize(1);
    const int top      = display.listStart();
    const int readout_y = display.height() - bigH - 1;   // size-2 readout baseline
    const int mid      = (top + readout_y) / 2;

    if (!gpsValid()) {
      display.drawTextCentered(cx, mid - ch / 2, "No GPS fix");
      return 1000;
    }

    int cog;
    bool have = _task->currentCourse(cog);

    if (!have) {
      display.drawTextCentered(cx, mid - ch, "move to");
      display.drawTextCentered(cx, mid,      "set heading");
      return 1000;
    }

    // ── heading tape ─────────────────────────────────────────────────────────
    // Centre of the tape = current course; bearings spread left/right at a fixed
    // pixels-per-degree. HALF_SPAN degrees reach each edge.
    const int area_x = 2;
    const int area_w = display.width() - 4;
    const float HALF_SPAN = 80.0f;                 // degrees visible to each side
    const float ppd = (area_w / 2.0f) / HALF_SPAN;

    // Tick/pointer sizes are authored at 1x and scaled by the font (same factor
    // the mini-icon framework uses), so they stay legible next to the 2x
    // cardinal labels and numeric readout on landscape e-ink.
    const int s  = miniIconScale(display);
    const int sh = display.sepH();        // baseline thickness (2px landscape e-ink, else 1)
    const int pointerH_units = 6;
    const int pointerH  = pointerH_units * s;
    const int tickMajor = 6 * s;
    const int tickMinor = 3 * s;
    const int blockH    = pointerH + sh + tickMajor + 2 + ch;
    const int block_top = top + ((readout_y - top) - blockH) / 2;
    const int line_y    = block_top + pointerH;     // scale baseline
    const int label_y   = line_y + sh + tickMajor + 2;
    const int x_lo = area_x, x_hi = area_x + area_w;

    // Scale baseline.
    display.fillRect(area_x, line_y, area_w, sh);

    // Ticks + cardinal labels every 30°; majors (N/E/S/W) are taller + labelled.
    for (int deg = 0; deg < 360; deg += 30) {
      int delta = deg - cog;
      while (delta >  180) delta -= 360;
      while (delta < -180) delta += 360;
      int x = cx + (int)(delta * ppd);
      if (x < x_lo || x > x_hi) continue;
      bool major = (deg % 90 == 0);
      display.fillRect(x - s / 2, line_y + sh, s, major ? tickMajor : tickMinor);
      if (major) {
        const char* letter = cardinalLetter(deg);
        display.setCursor(x - cw / 2, label_y);
        display.print(letter);
      }
    }

    // Fixed travel-direction pointer: a downward triangle whose tip touches the
    // baseline at screen centre (your current course always sits under it).
    // Each of the pointerH_units logical rows is drawn as an s-pixel-tall strip
    // — the same block-scaling miniIconDraw uses for bitmap icons.
    for (int i = 0; i < pointerH_units; i++) {
      int half = (pointerH_units - 1 - i) * s;
      display.fillRect(cx - half, block_top + i * s, 2 * half + 1, s);
    }

    // ── numeric readout ──────────────────────────────────────────────────────
    char buf[16];
    snprintf(buf, sizeof(buf), "%d %s", cog, geo::bearingCardinal(cog));
    display.setTextSize(2);
    display.drawTextCentered(cx, readout_y, buf);
    display.setTextSize(1);
    return 1000;
  }

  bool handleInput(char c) override {
    if (c == KEY_CANCEL || c == KEY_CONTEXT_MENU) { _task->gotoToolsScreen(); return true; }
    return true;
  }
};
