#pragma once
#include <cstdint>
#include <string>
#include <vector>

#include "core/Image.h"

namespace bmp2tile
{

// Which hardware palette representation to target. Matches the original
// tool's three palette output modes ("Output hex (SMS)" / "Output cl123
// (SMS)" / "Output hex (GG)") -- Cl123 is text-only (symbolic constant
// names, no byte representation of its own), so it's not accepted by
// SavePaletteBin.
enum class PaletteFormat
{
    Sms,
    Gg,
    Cl123,
};

// Converts an 8-bit RGB colour to a Master System CRAM byte: 2 bits each of
// R, G, B, packed as --BBGGRR (confirmed against smspower.org's own
// palette documentation). This is a straightforward rounding
// quantization; it does not yet replicate the original tool's Meka/eSMS
// palette-matching heuristics, which is a known gap (see README TODOs).
uint8_t ToSmsColorByte(const Color& c);

// Converts an 8-bit RGB colour to a Game Gear CRAM word: 4 bits each of
// R, G, B, packed little-endian as two bytes "ggggrrrr 0000bbbb" (the
// exact byte layout, cross-checked against a documented GG<->SMS palette
// conversion writeup). Per the original tool's own documented behaviour
// ("it just shifts colours to their high 4 bits"), this doesn't do any
// smarter palette-matching -- it's channel>>4, nothing more.
uint16_t ToGgColorWord(const Color& c);

// Pads `palette` with black (0,0,0) entries up to 16 total, if it has
// fewer than 16 already; never truncates a palette that's already 16 or
// more. Matches the original tool's "always emit 16 colours" option --
// useful because SMS/GG hardware palettes are a fixed 16 entries, so
// code that assumes all 16 slots are meaningful (or just wants a
// complete, consistent palette table regardless of how few colours a
// particular image happens to use) may want the full 16 written out.
//
// This is deliberately a plain palette->palette transform rather than a
// parameter threaded through every Format*/Save function below: apply it
// to the palette yourself before calling any of them, if you want the
// padded version. Keeps those functions simple (they just format
// whatever palette they're given) and keeps this in exactly one place.
std::vector<Color> PadPaletteTo16(const std::vector<Color>& palette);

// Formats a palette as a comma-separated list of hex byte literals in SMS
// format, e.g. "$00,$3F,$0C" -- suitable for pasting into a WLA DX .inc
// file. This is a minimal version of the original's "Output hex (SMS)"
// mode. Pass the output of PadPaletteTo16() instead of `palette` directly
// if you want "always emit 16 colours" behaviour.
std::string FormatPaletteAsSmsHex(const std::vector<Color>& palette);

// Formats a palette as a comma-separated list of hex byte literals in GG
// format -- two bytes per colour, little-endian, e.g. "$F0,$0F,...".
// Matches the original's "Output hex (GG)" mode. Pass PadPaletteTo16()'s
// output instead of `palette` directly for "always emit 16 colours".
std::string FormatPaletteAsGgHex(const std::vector<Color>& palette);

// Formats a palette as a comma-separated list of "cl123"-style constant
// names -- "cl" followed by the SMS 2-bit R, G, B digits (each 0-3), e.g.
// "cl123,cl333,cl001". Matches the original's "Output cl123 (SMS)" mode:
// pair this with a project-side colours.inc that #defines each clRGB name
// to its SMS byte value (ToSmsColorByte's format), so source reads as
// readable colour names instead of opaque hex.
// Digit order R,G,B is verified against bmp2tile 0.67 reference output.
// Pass PadPaletteTo16()'s output instead of `palette` directly for
// "always emit 16 colours".
std::string FormatPaletteAsCl123Constants(const std::vector<Color>& palette);

// Writes `palette` to `path` as raw bytes: one byte per colour
// (ToSmsColorByte) for PaletteFormat::Sms, or two bytes per colour
// little-endian (ToGgColorWord) for PaletteFormat::Gg -- these are
// exactly the layouts SMS_loadBGPalette/SMS_loadSpritePalette and their
// GG equivalents in devkitSMS's SMSlib expect. Throws std::runtime_error
// if format is Cl123 (it has no binary representation -- matches the
// original tool's own "-binary ignored for cl123" behaviour) or if the
// file can't be written. Pass PadPaletteTo16()'s output instead of
// `palette` directly for "always emit 16 colours".
void SavePaletteBin(const std::string& path, const std::vector<Color>& palette, PaletteFormat format = PaletteFormat::Sms);

}  // namespace bmp2tile
