"use client";

import {
  AlignCenter,
  AlignJustify,
  AlignLeft,
  AlignRight,
  Baseline,
  Bold,
  ChevronDown,
  ChevronUp,
  Highlighter,
  Italic,
  List,
  Strikethrough,
  Underline,
} from "lucide-react";
import { useRef } from "react";
import type { FabricObject, Textbox } from "fabric";
import { FONT_FAMILIES, isTextObject } from "@/lib/editor/objects";

interface FormatBarProps {
  selected: FabricObject | null;
  /** Bumped by the shell on object:modified so the bar re-reads values. */
  version: number;
  onChange: () => void;
}

const LINE_SPACINGS = [1, 1.15, 1.5, 2] as const;

function FormatToggle({
  icon: Icon,
  label,
  active,
  disabled,
  onClick,
}: {
  icon: React.ComponentType<{ className?: string }>;
  label: string;
  active?: boolean;
  disabled?: boolean;
  onClick: () => void;
}) {
  return (
    <button
      type="button"
      title={label}
      aria-label={label}
      aria-pressed={active}
      disabled={disabled}
      onClick={onClick}
      className={`flex h-7 w-7 items-center justify-center rounded transition-colors disabled:cursor-default disabled:opacity-35 ${
        active
          ? "bg-brand-100 text-brand-700 dark:bg-brand-600 dark:text-white"
          : "text-slate-600 hover:bg-slate-100 dark:text-slate-300 dark:hover:bg-slate-700"
      }`}
    >
      <Icon className="h-4 w-4" />
    </button>
  );
}

function Divider() {
  return <span className="mx-1.5 h-5 w-px shrink-0 bg-slate-200 dark:bg-slate-700" />;
}

function ColorSwatchButton({
  icon: Icon,
  label,
  color,
  disabled,
  onPick,
}: {
  icon: React.ComponentType<{ className?: string }>;
  label: string;
  color: string;
  disabled?: boolean;
  onPick: (color: string) => void;
}) {
  const inputRef = useRef<HTMLInputElement>(null);
  return (
    <button
      type="button"
      title={label}
      aria-label={label}
      disabled={disabled}
      onClick={() => inputRef.current?.click()}
      className="relative flex h-7 w-8 flex-col items-center justify-center rounded text-slate-600 transition-colors hover:bg-slate-100 disabled:cursor-default disabled:opacity-35 dark:text-slate-300 dark:hover:bg-slate-700"
    >
      <Icon className="h-3.5 w-3.5" />
      <span className="mt-0.5 h-1 w-5 rounded-sm" style={{ backgroundColor: color }} />
      <input
        ref={inputRef}
        type="color"
        value={color}
        disabled={disabled}
        onChange={(e) => onPick(e.target.value)}
        className="pointer-events-none absolute inset-0 opacity-0"
        tabIndex={-1}
        aria-hidden
      />
    </button>
  );
}

function toggleBullets(text: Textbox): string {
  const lines = (text.text ?? "").split("\n");
  const allBulleted = lines.every((l) => l.trim() === "" || l.startsWith("• "));
  return lines
    .map((l) => {
      if (l.trim() === "") return l;
      return allBulleted ? l.replace(/^• /, "") : l.startsWith("• ") ? l : `• ${l}`;
    })
    .join("\n");
}

export function FormatBar({ selected, onChange }: FormatBarProps) {
  const text = selected && isTextObject(selected) ? selected : null;
  const disabled = !text;

  function set(values: Record<string, unknown>) {
    if (!text) return;
    text.set(values);
    text.setCoords();
    onChange();
  }

  const fontSize = text ? Math.round(Number(text.fontSize ?? 14)) : 14;
  const fill = text && typeof text.fill === "string" && text.fill.startsWith("#") ? text.fill : "#111827";
  const highlight =
    text && typeof text.textBackgroundColor === "string" && text.textBackgroundColor.startsWith("#")
      ? text.textBackgroundColor
      : "#fde047";
  const lineHeight = text ? Number(text.lineHeight ?? 1.16) : 1.15;
  const spacingValue = LINE_SPACINGS.find((s) => Math.abs(s - lineHeight) < 0.03);
  const bulleted = Boolean(
    text && (text.text ?? "").split("\n").some((l) => l.startsWith("• ")),
  );

  const fieldCls =
    "h-7 rounded border border-slate-300 bg-white text-sm text-slate-900 disabled:opacity-35 dark:border-slate-600 dark:bg-slate-800 dark:text-slate-100";

  return (
    <div className="flex h-11 shrink-0 items-center overflow-x-auto border-b border-slate-200 bg-white px-3 dark:border-slate-700 dark:bg-slate-800">
      {/* Font group */}
      <select
        aria-label="Font family"
        className={`${fieldCls} w-36 px-1.5`}
        disabled={disabled}
        value={text ? String(text.fontFamily ?? "Helvetica") : "Helvetica"}
        onChange={(e) => set({ fontFamily: e.target.value })}
      >
        {FONT_FAMILIES.map((f) => (
          <option key={f} value={f}>
            {f}
          </option>
        ))}
      </select>

      <input
        type="number"
        aria-label="Font size"
        min={6}
        max={200}
        className={`${fieldCls} ml-1.5 w-14 px-1.5`}
        disabled={disabled}
        value={fontSize}
        onChange={(e) => set({ fontSize: Math.min(200, Math.max(6, Number(e.target.value) || 14)) })}
      />
      <div className="ml-0.5 flex flex-col">
        <button
          type="button"
          title="Increase font size"
          aria-label="Increase font size"
          disabled={disabled}
          onClick={() => set({ fontSize: Math.min(200, fontSize + 1) })}
          className="flex h-3.5 w-5 items-center justify-center rounded-sm text-slate-500 hover:bg-slate-100 disabled:opacity-35 dark:text-slate-400 dark:hover:bg-slate-700"
        >
          <ChevronUp className="h-3 w-3" />
        </button>
        <button
          type="button"
          title="Decrease font size"
          aria-label="Decrease font size"
          disabled={disabled}
          onClick={() => set({ fontSize: Math.max(6, fontSize - 1) })}
          className="flex h-3.5 w-5 items-center justify-center rounded-sm text-slate-500 hover:bg-slate-100 disabled:opacity-35 dark:text-slate-400 dark:hover:bg-slate-700"
        >
          <ChevronDown className="h-3 w-3" />
        </button>
      </div>

      <Divider />

      <FormatToggle
        icon={Bold}
        label="Bold"
        disabled={disabled}
        active={text?.fontWeight === "bold"}
        onClick={() => set({ fontWeight: text?.fontWeight === "bold" ? "normal" : "bold" })}
      />
      <FormatToggle
        icon={Italic}
        label="Italic"
        disabled={disabled}
        active={text?.fontStyle === "italic"}
        onClick={() => set({ fontStyle: text?.fontStyle === "italic" ? "normal" : "italic" })}
      />
      <FormatToggle
        icon={Underline}
        label="Underline"
        disabled={disabled}
        active={Boolean(text?.underline)}
        onClick={() => set({ underline: !text?.underline })}
      />
      <FormatToggle
        icon={Strikethrough}
        label="Strikethrough"
        disabled={disabled}
        active={Boolean(text?.linethrough)}
        onClick={() => set({ linethrough: !text?.linethrough })}
      />

      <Divider />

      <ColorSwatchButton icon={Baseline} label="Text color" color={fill} disabled={disabled} onPick={(c) => set({ fill: c })} />
      <ColorSwatchButton
        icon={Highlighter}
        label="Text highlight color"
        color={highlight}
        disabled={disabled}
        onPick={(c) => set({ textBackgroundColor: c })}
      />
      <FormatToggle
        icon={Highlighter}
        label={text?.textBackgroundColor ? "Remove highlight" : "Apply highlight"}
        disabled={disabled}
        active={Boolean(text?.textBackgroundColor)}
        onClick={() => set({ textBackgroundColor: text?.textBackgroundColor ? "" : highlight })}
      />

      <Divider />

      {/* Paragraph group */}
      {(
        [
          ["left", AlignLeft, "Align left"],
          ["center", AlignCenter, "Align center"],
          ["right", AlignRight, "Align right"],
          ["justify", AlignJustify, "Justify"],
        ] as const
      ).map(([align, Icon, label]) => (
        <FormatToggle
          key={align}
          icon={Icon}
          label={label}
          disabled={disabled}
          active={text?.textAlign === align}
          onClick={() => set({ textAlign: align })}
        />
      ))}

      <Divider />

      <select
        aria-label="Line spacing"
        title="Line spacing"
        className={`${fieldCls} w-16 px-1`}
        disabled={disabled}
        value={spacingValue !== undefined ? String(spacingValue) : "custom"}
        onChange={(e) => set({ lineHeight: Number(e.target.value) })}
      >
        {spacingValue === undefined && <option value="custom">{lineHeight.toFixed(2)}</option>}
        {LINE_SPACINGS.map((s) => (
          <option key={s} value={s}>
            {s === 1 ? "1.0" : String(s)}
          </option>
        ))}
      </select>

      <FormatToggle
        icon={List}
        label="Bullet list"
        disabled={disabled}
        active={bulleted}
        onClick={() => text && set({ text: toggleBullets(text) })}
      />

      {disabled && (
        <span className="ml-3 hidden whitespace-nowrap text-xs text-slate-400 dark:text-slate-500 md:inline">
          Select a text object to format it
        </span>
      )}
    </div>
  );
}
