"use client";

import type { TextBlockProps } from "@/features/editor/state/editorStore";
import { PropertySliderField } from "@/features/editor/components/PropertySliderField";
import { ColorPickerField, TEXT_COLOR_PALETTE } from "@/features/editor/components/ColorPickerField";
import { NumericPropertyControl } from "@/features/editor/components/NumericPropertyControl";

export type TextPropertiesPanelProps = {
  textProps: TextBlockProps;
  selectedBlockId: string;
  updateBlock: (id: string, partial: Partial<TextBlockProps>) => void;
  editingBlockId: string | null;
  setEditingText: (value: string) => void;
};

export function TextPropertiesPanel({
  textProps,
  selectedBlockId,
  updateBlock,
  editingBlockId,
  setEditingText,
}: TextPropertiesPanelProps) {
  const fontSizeMode = textProps.fontSizeMode ?? "scale";
  const fallbackScale =
    textProps.size === "sm" ? "sm" : textProps.size === "lg" ? "lg" : "base";
  const fontSizeScale = textProps.fontSizeScale ?? fallbackScale;
  const lineHeightMode = textProps.lineHeightMode ?? "scale";
  const lineHeightScale = textProps.lineHeightScale ?? "normal";
  const fontWeightMode = textProps.fontWeightMode ?? "scale";
  const fontWeightScale = textProps.fontWeightScale ?? "normal";
  const colorPalette = textProps.colorPalette ?? "default";
  const maxWidthMode = textProps.maxWidthMode ?? "scale";
  const maxWidthScale = textProps.maxWidthScale ?? "none";

  const fontSizeScaleToPx: Record<NonNullable<TextBlockProps["fontSizeScale"]>, number> = {
    xs: 12,
    sm: 14,
    base: 16,
    lg: 18,
    xl: 20,
    "2xl": 24,
    "3xl": 30,
  };

  const parsedFontSize = (() => {
    const raw = textProps.fontSizeCustom ?? "";
    const match = raw.match(/([0-9]+(?:\.[0-9]+)?)/);
    if (match) return Number(match[1]);
    return fontSizeScaleToPx[fontSizeScale];
  })();

  const parsedLineHeight = (() => {
    const raw = textProps.lineHeightCustom ?? "";
    const match = raw.match(/(-?[0-9]+(?:\.[0-9]+)?)/);
    if (match) return Number(match[1]);
    return 1.5;
  })();

  // 글자 간격: 내부 저장은 em 이지만, UI 에서는 px 단위로 보여준다.
  const parsedLetterSpacingPx = (() => {
    const raw = textProps.letterSpacingCustom ?? "";
    const match = raw.match(/(-?[0-9]+(?:\.[0-9]+)?)/);
    if (match) {
      const em = Number(match[1]);
      if (Number.isFinite(em)) {
        return em * 16; // 1em = 16px 기준으로 환산
      }
    }
    return 0;
  })();

  const letterSpacingPreset = (() => {
    const px = parsedLetterSpacingPx;
    if (px <= -1) return "tighter" as const;
    if (px < 0) return "tight" as const;
    if (px < 1) return "normal" as const;
    if (px < 3) return "wide" as const;
    return "wider" as const;
  })();

  const parsedFontWeight = (() => {
    const raw = textProps.fontWeightCustom ?? "";
    const match = raw.match(/([0-9]{3})/);
    if (match) return Number(match[1]);
    switch (fontWeightScale) {
      case "medium":
        return 500;
      case "semibold":
        return 600;
      case "bold":
        return 700;
      default:
        return 400;
    }
  })();

  return (
    <>
      <div className="space-y-1">
        <p className="text-xs text-slate-400">선택한 텍스트 블록 내용</p>
        <textarea
          className="w-full min-h-[80px] rounded border border-slate-700 bg-slate-900 px-2 py-1 text-xs outline-none focus:border-sky-500"
          aria-label="선택한 텍스트 블록 내용"
          value={textProps.text}
          onChange={(e) => {
            const value = e.target.value;
            updateBlock(selectedBlockId, { text: value });
            if (editingBlockId === selectedBlockId) {
              setEditingText(value);
            }
          }}
        />
      </div>

      <div className="space-y-1">
        <label className="flex flex-col gap-1 text-xs text-slate-400">
          <span>정렬</span>
          <select
            className="rounded border border-slate-700 bg-slate-900 px-2 py-1 text-xs outline-none focus:border-sky-500"
            aria-label="정렬"
            value={textProps.align}
            onChange={(e) => {
              const value = e.target.value as "left" | "center" | "right";
              updateBlock(selectedBlockId, { align: value });
            }}
          >
            <option value="left">왼쪽</option>
            <option value="center">가운데</option>
            <option value="right">오른쪽</option>
          </select>
        </label>
      </div>

      <div className="space-y-1">
        <div className="flex items-center justify-between text-[11px] text-slate-400">
          <span>텍스트 스타일</span>
          <div className="flex gap-1">
            <button
              type="button"
              className={`px-2 py-0.5 rounded border text-[11px] ${
                textProps.underline
                  ? "border-sky-500 bg-sky-900/40 text-sky-100"
                  : "border-slate-700 bg-slate-900 text-slate-300"
              }`}
              onClick={() => {
                updateBlock(selectedBlockId, {
                  underline: !textProps.underline,
                } as any);
              }}
            >
              밑줄
            </button>
            <button
              type="button"
              className={`px-2 py-0.5 rounded border text-[11px] ${
                textProps.strike
                  ? "border-sky-500 bg-sky-900/40 text-sky-100"
                  : "border-slate-700 bg-slate-900 text-slate-300"
              }`}
              onClick={() => {
                updateBlock(selectedBlockId, {
                  strike: !textProps.strike,
                } as any);
              }}
            >
              가운데줄
            </button>
            <button
              type="button"
              className={`px-2 py-0.5 rounded border text-[11px] ${
                textProps.italic
                  ? "border-sky-500 bg-sky-900/40 text-sky-100"
                  : "border-slate-700 bg-slate-900 text-slate-300"
              }`}
              onClick={() => {
                updateBlock(selectedBlockId, {
                  italic: !textProps.italic,
                } as any);
              }}
            >
              이탤릭
            </button>
          </div>
        </div>
      </div>

      <div className="space-y-1">
        <NumericPropertyControl
          label="글자 크기"
          unitLabel="(px)"
          value={Number.isFinite(parsedFontSize) ? parsedFontSize : 16}
          min={10}
          max={72}
          step={1}
          presets={(
            ["xs", "sm", "base", "lg", "xl", "2xl", "3xl"] as NonNullable<
              TextBlockProps["fontSizeScale"]
            >[]
          ).map((scale) => ({
            id: scale,
            label:
              scale === "xs"
                ? "XS"
                : scale === "sm"
                ? "S"
                : scale === "base"
                ? "M"
                : scale === "lg"
                ? "L"
                : scale === "xl"
                ? "XL"
                : scale === "2xl"
                ? "2XL"
                : "3XL",
            value: fontSizeScaleToPx[scale],
          }))}
          onChangeValue={(px) => {
            const raw = textProps.fontSizeCustom ?? "";
            const suffixMatch = raw.match(/px|rem|em|%/);
            const suffix = suffixMatch ? suffixMatch[0] : "px";

            const entries = Object.entries(fontSizeScaleToPx) as [
              NonNullable<TextBlockProps["fontSizeScale"]>,
              number,
            ][];
            const closest = entries.reduce(
              (best, [scale, value]) => {
                const dist = Math.abs(value - px);
                if (dist < best.dist) return { scale, dist };
                return best;
              },
              { scale: fontSizeScale as NonNullable<TextBlockProps["fontSizeScale"]>, dist: Infinity },
            ).scale;

            updateBlock(selectedBlockId, {
              fontSizeScale: closest,
              fontSizeCustom: `${px}${suffix}`,
              fontSizeMode: "custom",
            } as any);
          }}
        />
      </div>

      <div className="space-y-1">
        <label className="flex flex-col gap-1 text-xs text-slate-400">
          <span>글자 간격</span>
          <div className="flex items-center gap-2">
            <select
              className="w-32 rounded border border-slate-700 bg-slate-900 px-2 py-1 text-[11px] outline-none focus:border-sky-500"
              aria-label="글자 간격 프리셋"
              value={letterSpacingPreset}
              onChange={(e) => {
                const preset = e.target.value as
                  | "tighter"
                  | "tight"
                  | "normal"
                  | "wide"
                  | "wider";

                const presetPxMap: Record<
                  "tighter" | "tight" | "normal" | "wide" | "wider",
                  number
                > = {
                  tighter: -1.5,
                  tight: -0.5,
                  normal: 0,
                  wide: 1,
                  wider: 2,
                };

                const px = presetPxMap[preset];
                const em = px / 16;

                updateBlock(selectedBlockId, {
                  letterSpacingCustom: `${em}em`,
                } as any);
              }}
            >
              <option value="tighter">아주 좁게</option>
              <option value="tight">좁게</option>
              <option value="normal">보통</option>
              <option value="wide">넓게</option>
              <option value="wider">아주 넓게</option>
            </select>

            <PropertySliderField
              label=""
              ariaLabelSlider="글자 간격 슬라이더"
              ariaLabelInput="글자 간격 커스텀 (px)"
              value={Number.isFinite(parsedLetterSpacingPx) ? parsedLetterSpacingPx : 0}
              min={-2}
              max={10}
              step={0.1}
              onChange={(px) => {
                const em = px / 16;
                updateBlock(selectedBlockId, {
                  letterSpacingCustom: `${em}em`,
                } as any);
              }}
            />
          </div>
        </label>
      </div>

      <div className="space-y-1">
        <NumericPropertyControl
          label="줄 간격"
          unitLabel=""
          value={Number.isFinite(parsedLineHeight) ? parsedLineHeight : 1.5}
          min={-1}
          max={3}
          step={0.05}
          presets={[
            { id: "tight", label: "좁게", value: 1.25 },
            { id: "snug", label: "약간 좁게", value: 1.35 },
            { id: "normal", label: "보통", value: 1.5 },
            { id: "relaxed", label: "넓게", value: 1.7 },
            { id: "loose", label: "아주 넓게", value: 1.9 },
          ]}
          onChangeValue={(v) => {
            const preset: Record<NonNullable<TextBlockProps["lineHeightScale"]>, number> = {
              tight: 1.25,
              snug: 1.35,
              normal: 1.5,
              relaxed: 1.7,
              loose: 1.9,
            };

            const entries = Object.entries(preset) as [
              NonNullable<TextBlockProps["lineHeightScale"]>,
              number,
            ][];
            const closest = entries.reduce(
              (best, [scale, value]) => {
                const dist = Math.abs(value - v);
                if (dist < best.dist) return { scale, dist };
                return best;
              },
              { scale: lineHeightScale as NonNullable<TextBlockProps["lineHeightScale"]>, dist: Infinity },
            ).scale;

            updateBlock(selectedBlockId, {
              lineHeightScale: closest,
              lineHeightCustom: v.toString(),
              lineHeightMode: "custom",
            } as any);
          }}
        />
      </div>

      <div className="space-y-1">
        <NumericPropertyControl
          label="굵기"
          value={Number.isFinite(parsedFontWeight) ? parsedFontWeight : 400}
          min={100}
          max={900}
          step={100}
          presets={(
            ["normal", "medium", "semibold", "bold"] as NonNullable<
              TextBlockProps["fontWeightScale"]
            >[]
          ).map((scale) => ({
            id: scale,
            label:
              scale === "normal"
                ? "보통"
                : scale === "medium"
                ? "중간"
                : scale === "semibold"
                ? "세미볼드"
                : "볼드",
            value:
              scale === "normal"
                ? 400
                : scale === "medium"
                ? 500
                : scale === "semibold"
                ? 600
                : 700,
          }))}
          onChangeValue={(v) => {
            const preset: Record<NonNullable<TextBlockProps["fontWeightScale"]>, number> = {
              normal: 400,
              medium: 500,
              semibold: 600,
              bold: 700,
            };

            const entries = Object.entries(preset) as [
              NonNullable<TextBlockProps["fontWeightScale"]>,
              number,
            ][];
            const closest = entries.reduce(
              (best, [scale, value]) => {
                const dist = Math.abs(value - v);
                if (dist < best.dist) return { scale, dist };
                return best;
              },
              { scale: fontWeightScale as NonNullable<TextBlockProps["fontWeightScale"]>, dist: Infinity },
            ).scale;

            updateBlock(selectedBlockId, {
              fontWeightScale: closest,
              fontWeightCustom: v.toString(),
              fontWeightMode: "custom",
            } as any);
          }}
        />
      </div>

      <div className="space-y-1">
        <ColorPickerField
          label="텍스트 색상"
          ariaLabelColorInput="텍스트 색상 피커"
          ariaLabelHexInput="텍스트 색상 HEX"
          value={
            (textProps.colorCustom && textProps.colorCustom.startsWith("#")
              ? textProps.colorCustom
              : TEXT_COLOR_PALETTE.find((p) => p.id === colorPalette)?.color ?? "#ffffff")
          }
          onChange={(hex) => {
            updateBlock(selectedBlockId, {
              colorCustom: hex,
              colorMode: "custom",
            } as any);
          }}
          palette={TEXT_COLOR_PALETTE}
          selectedPaletteId={colorPalette}
          onPaletteSelect={(item) => {
            const paletteId = item.id as NonNullable<TextBlockProps["colorPalette"]>;
            updateBlock(selectedBlockId, {
              colorPalette: paletteId,
              colorCustom: item.color,
              colorMode: "custom",
            } as any);
          }}
        />
      </div>

      <div className="space-y-1">
        <ColorPickerField
          label="블록 배경색"
          ariaLabelColorInput="텍스트 블록 배경색 피커"
          ariaLabelHexInput="텍스트 블록 배경색 HEX"
          value={textProps.backgroundColorCustom ?? ""}
          onChange={(hex) => {
            updateBlock(selectedBlockId, {
              backgroundColorCustom: hex,
            } as any);
          }}
          palette={TEXT_COLOR_PALETTE}
        />
      </div>

      <div className="space-y-1">
        <label className="flex flex-col gap-1 text-xs text-slate-400">
          <span>최대 너비</span>
          <div className="flex items-center gap-2">
            <select
              className="w-32 rounded border border-slate-700 bg-slate-900 px-2 py-1 text-[11px] outline-none focus:border-sky-500"
              aria-label="최대 너비 프리셋"
              value={maxWidthScale}
              onChange={(e) => {
                const value = e.target.value as NonNullable<TextBlockProps["maxWidthScale"]>;
                let custom = textProps.maxWidthCustom ?? "";
                if (value === "prose") custom = "60ch";
                else if (value === "narrow") custom = "40ch";
                else custom = "";
                updateBlock(selectedBlockId, {
                  maxWidthScale: value,
                  maxWidthMode: custom ? "custom" : "scale",
                  maxWidthCustom: custom,
                } as any);
              }}
            >
              <option value="none">제한 없음</option>
              <option value="prose">본문 폭 (60ch)</option>
              <option value="narrow">좁게 (40ch)</option>
            </select>
            <input
              type="range"
              min={20}
              max={120}
              step={5}
              aria-label="최대 너비 슬라이더 (ch 단위)"
              value={(() => {
                const raw = textProps.maxWidthCustom ?? "";
                const match = raw.match(/([0-9]+)ch/);
                if (match) return Number(match[1]);
                if (maxWidthScale === "prose") return 60;
                if (maxWidthScale === "narrow") return 40;
                return 120;
              })()}
              onChange={(e) => {
                const ch = Number(e.target.value || 60);
                updateBlock(selectedBlockId, {
                  maxWidthCustom: `${ch}ch`,
                  maxWidthMode: "custom",
                } as any);
              }}
              className="flex-1"
            />
          </div>
          <input
            className="w-full rounded border border-slate-700 bg-slate-900 px-2 py-1 text-xs outline-none focus:border-sky-500"
            aria-label="최대 너비 커스텀"
            placeholder="예: 600px, 40rem, 80%, 60ch"
            value={textProps.maxWidthCustom ?? ""}
            onChange={(e) => {
              updateBlock(selectedBlockId, {
                maxWidthCustom: e.target.value,
                maxWidthMode: "custom",
              } as any);
            }}
          />
        </label>
      </div>
    </>
  );
}
