import type { ToolInput } from "../../core/io/input-types";
import type { ToolResult } from "../../core/io/output-types";
import type { ToolContext } from "../../core/plugins/plugin-types";
import type { ColorConverterOptions } from "./index";

interface RGB { r: number; g: number; b: number; }

function parseHex(input: string): RGB | null {
  const match = input.match(/^#?([0-9a-f]{3,8})$/i);
  if (!match) return null;
  let hex = match[1];
  if (hex.length === 3) {
    hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
  }
  if (hex.length === 4) {
    hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
  }
  if (hex.length >= 6) {
    return {
      r: parseInt(hex.substring(0, 2), 16),
      g: parseInt(hex.substring(2, 4), 16),
      b: parseInt(hex.substring(4, 6), 16),
    };
  }
  return null;
}

function parseRgb(input: string): RGB | null {
  const match = input.match(/rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})/);
  if (!match) return null;
  return {
    r: Math.min(255, parseInt(match[1], 10)),
    g: Math.min(255, parseInt(match[2], 10)),
    b: Math.min(255, parseInt(match[3], 10)),
  };
}

function parseHsl(input: string): RGB | null {
  const match = input.match(/hsla?\(\s*(\d{1,3})\s*,\s*(\d{1,3})%?\s*,\s*(\d{1,3})%?/);
  if (!match) return null;
  const h = parseInt(match[1], 10) / 360;
  const s = parseInt(match[2], 10) / 100;
  const l = parseInt(match[3], 10) / 100;

  if (s === 0) {
    const v = Math.round(l * 255);
    return { r: v, g: v, b: v };
  }

  const hue2rgb = (p: number, q: number, t: number): number => {
    if (t < 0) t += 1;
    if (t > 1) t -= 1;
    if (t < 1 / 6) return p + (q - p) * 6 * t;
    if (t < 1 / 2) return q;
    if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
    return p;
  };

  const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
  const p = 2 * l - q;

  return {
    r: Math.round(hue2rgb(p, q, h + 1 / 3) * 255),
    g: Math.round(hue2rgb(p, q, h) * 255),
    b: Math.round(hue2rgb(p, q, h - 1 / 3) * 255),
  };
}

function parseColor(input: string): RGB | null {
  const trimmed = input.trim().toLowerCase();
  return parseHex(trimmed) || parseRgb(trimmed) || parseHsl(trimmed);
}

function rgbToHex(rgb: RGB): string {
  const toHex = (n: number) => n.toString(16).padStart(2, "0");
  return `#${toHex(rgb.r)}${toHex(rgb.g)}${toHex(rgb.b)}`;
}

function rgbToHsl(rgb: RGB): { h: number; s: number; l: number } {
  const r = rgb.r / 255;
  const g = rgb.g / 255;
  const b = rgb.b / 255;
  const max = Math.max(r, g, b);
  const min = Math.min(r, g, b);
  const l = (max + min) / 2;

  if (max === min) return { h: 0, s: 0, l: Math.round(l * 100) };

  const d = max - min;
  const s = l > 0.5 ? d / (2 - max - min) : d / (max + min);

  const h =
    max === r
      ? ((g - b) / d + (g < b ? 6 : 0)) / 6
      : max === g
        ? ((b - r) / d + 2) / 6
        : ((r - g) / d + 4) / 6;

  return {
    h: Math.round(h * 360),
    s: Math.round(s * 100),
    l: Math.round(l * 100),
  };
}

export async function runColorConverter(
  input: ToolInput,
  options: ColorConverterOptions,
  context?: ToolContext
): Promise<ToolResult> {
  void context;

  const text = input.text || "";
  if (!text.trim()) {
    throw new Error("No color value provided.");
  }

  const rgb = parseColor(text);
  if (!rgb) {
    throw new Error("Unrecognized color format. Use HEX (#ff0000), RGB (rgb(255,0,0)), or HSL (hsl(0,100%,50%)).");
  }

  const hex = rgbToHex(rgb);
  const hsl = rgbToHsl(rgb);

  let primary: string;
  switch (options.format) {
    case "hex":
      primary = hex;
      break;
    case "rgb":
      primary = `rgb(${rgb.r}, ${rgb.g}, ${rgb.b})`;
      break;
    case "hsl":
      primary = `hsl(${hsl.h}, ${hsl.s}%, ${hsl.l}%)`;
      break;
    default:
      primary = hex;
  }

  return {
    type: "json",
    value: {
      hex,
      rgb: `rgb(${rgb.r}, ${rgb.g}, ${rgb.b})`,
      hsl: `hsl(${hsl.h}, ${hsl.s}%, ${hsl.l}%)`,
      primary,
      channels: { r: rgb.r, g: rgb.g, b: rgb.b },
    },
  };
}
