local createVersion = require('/apis/libversion');

local args = table.pack(...);

local FACE = {
  'LlGgLlGg',
  'lGGllGGL',
  'GXXggXXG',
  'gXXGGXXg',
  'LGGXXGGl',
  'gGXXXXGg',
  'LGXggXGL',
  'gGGLLGGg',
};

local THEMES = {
  vanilla = {
    title = 'Creeper',
    background = colors.black,
    text = colors.white,
    palette = {
      G = colors.green,
      g = colors.lime,
      L = colors.lightGray,
      l = colors.gray,
      X = colors.black,
    },
  },
  charged = {
    title = 'Charged Creeper',
    background = colors.black,
    text = colors.white,
    palette = {
      G = colors.blue,
      g = colors.cyan,
      L = colors.lightBlue,
      l = colors.white,
      X = colors.black,
    },
  },
  magma = {
    title = 'Magma Creeper',
    background = colors.black,
    text = colors.orange,
    palette = {
      G = colors.red,
      g = colors.orange,
      L = colors.yellow,
      l = colors.brown,
      X = colors.black,
    },
  },
  ocean = {
    title = 'Ocean Creeper',
    background = colors.black,
    text = colors.lightBlue,
    palette = {
      G = colors.blue,
      g = colors.lightBlue,
      L = colors.cyan,
      l = colors.blue,
      X = colors.black,
    },
  },
  sand = {
    title = 'Sand Creeper',
    background = colors.black,
    text = colors.yellow,
    palette = {
      G = colors.yellow,
      g = colors.orange,
      L = colors.white,
      l = colors.lightGray,
      X = colors.brown,
    },
  },
};

local THEME_NAMES = { 'vanilla', 'charged', 'magma', 'ocean', 'sand' };

local function printUsage()
  print('creeper usage:');
  print();
  print('  creeper');
  print('  creeper <theme>');
  print('  creeper --theme <theme>');
  print('  creeper --random');
  print('  creeper --version');
  print('  creeper --help');
  print();
  print('themes: vanilla, charged, magma, ocean, sand');
  print();
  print('examples:');
  print('  creeper charged');
  print('  creeper --theme sand');
  print('  creeper --random');
end

local function drawRun(x, y, len, color)
  term.setBackgroundColor(color);
  term.setCursorPos(x, y);
  term.write(string.rep(' ', len));
end

local function themeNamesText()
  return table.concat(THEME_NAMES, ', ');
end

local function parseArgs(argv)
  local selectedTheme = 'vanilla';
  local selectedExplicitly = false;
  local randomTheme = false;
  local index = 1;

  while index <= argv.n do
    local arg = argv[index];

    if arg == '--random' or arg == '-random' then
      if selectedExplicitly then
        return nil, '--random cannot be combined with a theme';
      end
      randomTheme = true;
    elseif arg == '--theme' or arg == '-theme' then
      if randomTheme or selectedExplicitly then
        return nil, arg .. ' cannot be combined with another theme option';
      end
      index = index + 1;
      selectedTheme = argv[index];
      if selectedTheme == nil then
        return nil, 'missing theme after ' .. arg;
      end
      selectedExplicitly = true;
    elseif THEMES[arg] ~= nil then
      if randomTheme or selectedExplicitly then
        return nil, arg .. ' cannot be combined with another theme option';
      end
      selectedTheme = arg;
      selectedExplicitly = true;
    else
      return nil, 'unknown option or theme: ' .. tostring(arg);
    end

    index = index + 1;
  end

  if randomTheme then
    math.randomseed(os.epoch('utc'));
    selectedTheme = THEME_NAMES[math.random(1, #THEME_NAMES)];
  end

  if THEMES[selectedTheme] == nil then
    return nil, 'unknown theme: ' .. tostring(selectedTheme)
      .. ' (available: ' .. themeNamesText() .. ')';
  end

  return THEMES[selectedTheme];
end

local function drawCreeper(theme)
  local width, height = term.getSize();
  local pixelW = math.max(1, math.floor(width / 12));
  local pixelH = math.max(1, math.floor(height / 12));

  if pixelW < 2 and width >= #FACE[1] * 2 then pixelW = 2; end
  if pixelW > 4 then pixelW = 4; end
  if pixelH > 3 then pixelH = 3; end

  local artW = #FACE[1] * pixelW;
  local artH = #FACE * pixelH;
  local startX = math.max(1, math.floor((width - artW) / 2) + 1);
  local startY = math.max(1, math.floor((height - artH) / 2) + 1);

  term.setBackgroundColor(theme.background);
  term.setTextColor(theme.text);
  term.clear();

  for row = 1, #FACE do
    for sy = 0, pixelH - 1 do
      local y = startY + ((row - 1) * pixelH) + sy;
      local col = 1;
      while col <= #FACE[row] do
        local token = FACE[row]:sub(col, col);
        local run = 1;

        while col + run <= #FACE[row]
          and FACE[row]:sub(col + run, col + run) == token do
          run = run + 1;
        end

        local color = theme.palette[token] or theme.palette.G;
        drawRun(startX + ((col - 1) * pixelW), y, run * pixelW, color);
        col = col + run;
      end
    end
  end

  term.setBackgroundColor(theme.background);
  term.setTextColor(theme.text);

  if height >= startY + artH then
    term.setCursorPos(math.max(1, math.floor((width - #theme.title) / 2) + 1), startY + artH + 1);
    term.write(theme.title);
  end

  term.setCursorPos(1, height);
end

local command = args[1];

if command == '-help' or command == '--help' or command == 'help' then
  printUsage();
  return;
end

if command == '-version' or command == '--version' or command == 'version' then
  print('v' .. createVersion().forSelf());
  return;
end

local theme, err = parseArgs(args);
if not theme then
  print(err);
  print('utilise: creeper -help');
  return;
end

drawCreeper(theme);
