/// Shared menu helpers for Wolf3D hosts.
library;

import 'package:wolf_3d_dart/wolf_3d_data_types.dart';

/// Known VGA picture indexes used by the original Wolf3D control-panel menus.
///
/// Values below are picture-table indexes (not raw chunk ids).
/// For example, `C_CONTROLPIC` is chunk 26 in `GFXV_WL6.H`, so its picture
/// index is `26 - STARTPICS(3) = 23`.
abstract class WolfMenuPic {
  static const int hBj = 0; // H_BJPIC
  static const int hTopWindow = 3; // H_TOPWINDOWPIC
  static const int cOptions = 7; // C_OPTIONSPIC
  static const int cCursor1 = 8; // C_CURSOR1PIC
  static const int cCursor2 = 9; // C_CURSOR2PIC
  static const int cNotSelected = 10; // C_NOTSELECTEDPIC
  static const int cSelected = 11; // C_SELECTEDPIC
  static const int cBabyMode = 16; // C_BABYMODEPIC
  static const int cEasy = 17; // C_EASYPIC
  static const int cNormal = 18; // C_NORMALPIC
  static const int cHard = 19; // C_HARDPIC
  static const int cControl = 23; // C_CONTROLPIC
  static const int cCustomize = 24; // C_CUSTOMIZEPIC
  static const int cEpisode1 = 27; // C_EPISODE1PIC
  static const int cEpisode2 = 28; // C_EPISODE2PIC
  static const int cEpisode3 = 29; // C_EPISODE3PIC
  static const int cEpisode4 = 30; // C_EPISODE4PIC
  static const int cEpisode5 = 31; // C_EPISODE5PIC
  static const int cEpisode6 = 32; // C_EPISODE6PIC
  static const int statusBar = 83; // STATUSBARPIC
  static const int title = 84; // TITLEPIC
  static const int pg13 = 85; // PG13PIC
  static const int credits = 86; // CREDITSPIC
  static const int highScores = 87; // HIGHSCORESPIC

  static const List<int> episodePics = [
    cEpisode1,
    cEpisode2,
    cEpisode3,
    cEpisode4,
    cEpisode5,
    cEpisode6,
  ];
}

/// Shared menu text colors resolved from the VGA palette.
///
/// Keep menu color choices centralized so renderers don't duplicate
/// hard-coded palette slots or RGB conversion logic.
abstract class WolfMenuPalette {
  static const int selectedTextIndex = 19;
  static const int unselectedTextIndex = 23;
  static const int disabledTextIndex = 4;
  static const int _headerTargetRgb = 0xFFF700;

  static int? _cachedHeaderTextIndex;

  static int get headerTextIndex =>
      _cachedHeaderTextIndex ??= _nearestPaletteIndex(_headerTargetRgb);

  static int get selectedTextColor => ColorPalette.vga32Bit[selectedTextIndex];

  static int get unselectedTextColor =>
      ColorPalette.vga32Bit[unselectedTextIndex];

  static int get disabledTextColor => ColorPalette.vga32Bit[disabledTextIndex];

  static int get headerTextColor => ColorPalette.vga32Bit[headerTextIndex];

  static int _nearestPaletteIndex(int rgb) {
    final int targetR = (rgb >> 16) & 0xFF;
    final int targetG = (rgb >> 8) & 0xFF;
    final int targetB = rgb & 0xFF;

    int bestIndex = 0;
    int bestDistance = 1 << 30;

    for (int i = 0; i < 256; i++) {
      final int color = ColorPalette.vga32Bit[i];
      final int r = color & 0xFF;
      final int g = (color >> 8) & 0xFF;
      final int b = (color >> 16) & 0xFF;

      final int dr = targetR - r;
      final int dg = targetG - g;
      final int db = targetB - b;
      final int distance = (dr * dr) + (dg * dg) + (db * db);
      if (distance < bestDistance) {
        bestDistance = distance;
        bestIndex = i;
      }
    }

    return bestIndex;
  }
}

/// Structured accessors for classic Wolf3D menu art.
class WolfClassicMenuArt {
  final WolfensteinData data;

  WolfClassicMenuArt(this.data);

  VgaImage? get controlBackground {
    return _imageForKey(MenuPicKey.controlBackground);
  }

  VgaImage? get title => _imageForKey(MenuPicKey.title);

  VgaImage? get heading => _imageForKey(MenuPicKey.heading);

  VgaImage? get selectedMarker => _imageForKey(MenuPicKey.markerSelected);

  VgaImage? get unselectedMarker => _imageForKey(MenuPicKey.markerUnselected);

  VgaImage? get optionsLabel => _imageForKey(MenuPicKey.optionsLabel);

  VgaImage? get customizeLabel => _imageForKey(MenuPicKey.customizeLabel);

  VgaImage? get credits => _imageForKey(MenuPicKey.credits);

  VgaImage? episodeOption(int episodeIndex) {
    if (episodeIndex < 0) {
      return null;
    }
    final key = data.registry.menu.episodeKey(episodeIndex);
    return _imageForKey(key);
  }

  VgaImage? difficultyOption(Difficulty difficulty) {
    final key = data.registry.menu.difficultyKey(difficulty);
    return _imageForKey(key);
  }

  /// Legacy numeric lookup API retained for existing renderer call sites.
  ///
  /// Known legacy indices are mapped through symbolic registry keys first.
  /// Unknown indices fall back to direct picture-table indexing.
  VgaImage? mappedPic(int index) {
    final key = _legacyKeyForIndex(index);
    if (key != null) {
      return _imageForKey(key);
    }
    return pic(index);
  }

  VgaImage? pic(int index) {
    if (index < 0 || index >= data.vgaImages.length) {
      return null;
    }
    final image = data.vgaImages[index];

    if (image.width <= 0 || image.height <= 0) {
      return null;
    }

    return image;
  }

  VgaImage? _imageForKey(MenuPicKey key) {
    final ref = data.registry.menu.resolve(key);
    if (ref == null) {
      return null;
    }
    return pic(ref.pictureIndex);
  }

  MenuPicKey? _legacyKeyForIndex(int index) {
    switch (index) {
      case WolfMenuPic.hTopWindow:
        return MenuPicKey.heading;
      case WolfMenuPic.cOptions:
        return MenuPicKey.optionsLabel;
      case WolfMenuPic.cCursor1:
        return MenuPicKey.cursorActive;
      case WolfMenuPic.cCursor2:
        return MenuPicKey.cursorInactive;
      case WolfMenuPic.cNotSelected:
        return MenuPicKey.markerUnselected;
      case WolfMenuPic.cSelected:
        return MenuPicKey.markerSelected;
      case 15:
        return MenuPicKey.footer;
      case WolfMenuPic.cBabyMode:
        return MenuPicKey.difficultyBaby;
      case WolfMenuPic.cEasy:
        return MenuPicKey.difficultyEasy;
      case WolfMenuPic.cNormal:
        return MenuPicKey.difficultyNormal;
      case WolfMenuPic.cHard:
        return MenuPicKey.difficultyHard;
      case WolfMenuPic.cControl:
        return MenuPicKey.controlBackground;
      case WolfMenuPic.cCustomize:
        return MenuPicKey.customizeLabel;
      case WolfMenuPic.cEpisode1:
        return MenuPicKey.episode1;
      case WolfMenuPic.cEpisode2:
        return MenuPicKey.episode2;
      case WolfMenuPic.cEpisode3:
        return MenuPicKey.episode3;
      case WolfMenuPic.cEpisode4:
        return MenuPicKey.episode4;
      case WolfMenuPic.cEpisode5:
        return MenuPicKey.episode5;
      case WolfMenuPic.cEpisode6:
        return MenuPicKey.episode6;
      case WolfMenuPic.title:
        return MenuPicKey.title;
      case WolfMenuPic.pg13:
        return MenuPicKey.pg13;
      case WolfMenuPic.credits:
        return MenuPicKey.credits;
      default:
        return null;
    }
  }
}
