import { useEffect, useRef, useState } from "react";
import { Plus, Type } from "../../icons/SystemIcons";
import { isTextEditableSelection, type DomEditSelection } from "./domEditing";
import type { ImportedFontAsset } from "./fontAssets";
import { FIELD, LABEL, normalizeTextMetricValue, RESPONSIVE_GRID } from "./propertyPanelHelpers";
import { MetricField, Section, SelectField } from "./propertyPanelPrimitives";
import { ColorField } from "./propertyPanelColor";
import { FontFamilyField } from "./propertyPanelFont";
import { PromotableControl } from "./PromotableControl";

/* ------------------------------------------------------------------ */
/*  Text helpers (used only by text section components)                */
/* ------------------------------------------------------------------ */

function formatTextFieldPreview(value: string): string {
  const collapsed = value.trim().replace(/\s+/g, " ");
  if (collapsed.length <= 56) return collapsed;
  return `${collapsed.slice(0, 55)}…`;
}

function getTextFieldColor(
  field: { computedStyles: Record<string, string> },
  inheritedStyles: Record<string, string>,
): string {
  return field.computedStyles.color || inheritedStyles.color || "rgb(0, 0, 0)";
}

function getTextStyleValue(
  field: { computedStyles: Record<string, string> },
  inheritedStyles: Record<string, string>,
  property: string,
  fallback: string,
): string {
  return field.computedStyles[property] || inheritedStyles[property] || fallback;
}

const ALL_WEIGHTS = ["100", "200", "300", "400", "500", "600", "700", "800", "900"];
const WEIGHT_LABELS: Record<string, string> = {
  "100": "100 · Thin",
  "200": "200 · Extra Light",
  "300": "300 · Light",
  "400": "400 · Regular",
  "500": "500 · Medium",
  "600": "600 · Semi Bold",
  "700": "700 · Bold",
  "800": "800 · Extra Bold",
  "900": "900 · Black",
};

function detectAvailableWeights(fontFamily: string): string[] {
  const fonts = document.fonts;
  if (!fonts) return ALL_WEIGHTS;
  const family = fontFamily.split(",")[0]?.trim().replace(/['"]/g, "");
  if (!family) return ALL_WEIGHTS;
  const available: string[] = [];
  for (const w of ALL_WEIGHTS) {
    if (fonts.check(`${w} 16px "${family}"`)) available.push(w);
  }
  return available.length > 0 ? available : ALL_WEIGHTS;
}

function TextAreaField({
  label,
  value,
  disabled,
  autoFocus,
  onCommit,
}: {
  label: string;
  value: string;
  disabled?: boolean;
  autoFocus?: boolean;
  onCommit: (nextValue: string) => void;
}) {
  const [draft, setDraft] = useState(value);
  const textareaRef = useRef<HTMLTextAreaElement | null>(null);
  const commitTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
  const focusedRef = useRef(false);
  const valueRef = useRef(value);
  valueRef.current = value;

  useEffect(() => {
    if (focusedRef.current) return;
    setDraft(value);
  }, [value]);
  useEffect(
    () => () => {
      if (commitTimerRef.current) clearTimeout(commitTimerRef.current);
    },
    [],
  );
  useEffect(() => {
    if (!autoFocus) return;
    textareaRef.current?.focus();
  }, [autoFocus]);

  const commitDraft = (d: string) => {
    if (commitTimerRef.current) clearTimeout(commitTimerRef.current);
    if (d !== valueRef.current) onCommit(d);
  };
  const scheduleCommit = (d: string) => {
    if (commitTimerRef.current) clearTimeout(commitTimerRef.current);
    commitTimerRef.current = setTimeout(() => {
      if (d !== valueRef.current) onCommit(d);
    }, 120);
  };

  return (
    <label className="grid min-w-0 gap-1.5">
      <span className={LABEL}>{label}</span>
      <div className={FIELD}>
        <textarea
          ref={textareaRef}
          value={draft}
          disabled={disabled}
          rows={4}
          onFocus={() => {
            focusedRef.current = true;
          }}
          onChange={(e) => {
            setDraft(e.target.value);
            scheduleCommit(e.target.value);
          }}
          onBlur={() => {
            focusedRef.current = false;
            commitDraft(draft);
          }}
          className="w-full resize-none bg-transparent text-[11px] font-medium text-neutral-100 outline-none disabled:cursor-not-allowed disabled:text-neutral-600"
        />
      </div>
    </label>
  );
}

function FontWeightField({
  value,
  disabled,
  fontFamily,
  onCommit,
}: {
  value: string;
  disabled?: boolean;
  fontFamily?: string;
  onCommit: (nextValue: string) => void;
}) {
  const options = fontFamily ? detectAvailableWeights(fontFamily) : ALL_WEIGHTS;
  const displayOptions = value && !options.includes(value) ? [value, ...options] : options;
  return (
    <div className={FIELD}>
      <div className="flex min-w-0 items-center gap-3">
        <span className="flex-shrink-0 text-[11px] font-medium text-neutral-500">Weight</span>
        <select
          value={value}
          disabled={disabled}
          onChange={(e) => onCommit(e.target.value)}
          className="min-w-0 w-full appearance-none bg-transparent text-[11px] font-medium text-neutral-100 outline-none disabled:cursor-not-allowed disabled:text-neutral-600"
        >
          {displayOptions.map((o) => (
            <option key={o} value={o}>
              {WEIGHT_LABELS[o] ?? o}
            </option>
          ))}
        </select>
      </div>
    </div>
  );
}

function AdvancedTextControls({
  field,
  inheritedStyles,
  disabled,
  onCommit,
}: {
  field: DomEditSelection["textFields"][number];
  inheritedStyles: Record<string, string>;
  disabled?: boolean;
  onCommit: (property: string, value: string) => void;
}) {
  return (
    <div className="space-y-4">
      <div className={RESPONSIVE_GRID}>
        <SelectField
          label="Line"
          value={getTextStyleValue(field, inheritedStyles, "line-height", "normal")}
          disabled={disabled}
          options={["normal", "1", "1.1", "1.2", "1.25", "1.3", "1.4", "1.5", "1.6", "1.75", "2"]}
          onChange={(n) => onCommit("line-height", normalizeTextMetricValue("line-height", n))}
        />
        <SelectField
          label="Track"
          value={getTextStyleValue(field, inheritedStyles, "letter-spacing", "0px")}
          disabled={disabled}
          options={[
            "0px",
            "-0.05em",
            "-0.04em",
            "-0.03em",
            "-0.02em",
            "-0.01em",
            "0em",
            "0.01em",
            "0.02em",
            "0.03em",
            "0.05em",
            "0.1em",
            "0.15em",
            "0.2em",
          ]}
          onChange={(n) =>
            onCommit("letter-spacing", normalizeTextMetricValue("letter-spacing", n))
          }
        />
      </div>
      <div className={RESPONSIVE_GRID}>
        <SelectField
          label="Align"
          value={getTextStyleValue(field, inheritedStyles, "text-align", "start")}
          disabled={disabled}
          onChange={(n) => onCommit("text-align", n)}
          options={["start", "left", "center", "right", "justify", "end"]}
        />
        <SelectField
          label="Case"
          value={getTextStyleValue(field, inheritedStyles, "text-transform", "none")}
          disabled={disabled}
          onChange={(n) => onCommit("text-transform", n)}
          options={["none", "uppercase", "lowercase", "capitalize"]}
        />
      </div>
      <SelectField
        label="Style"
        value={getTextStyleValue(field, inheritedStyles, "font-style", "normal")}
        disabled={disabled}
        onChange={(n) => onCommit("font-style", n)}
        options={["normal", "italic"]}
      />
    </div>
  );
}

/* ------------------------------------------------------------------ */
/*  Text section                                                       */
/* ------------------------------------------------------------------ */

function TextFieldEditor({
  field,
  styles,
  fontAssets,
  onImportFonts,
  showRemove,
  onSetText,
  onSetTextFieldStyle,
  onRemoveTextField,
}: {
  field: DomEditSelection["textFields"][number];
  styles: Record<string, string>;
  fontAssets: ImportedFontAsset[];
  onImportFonts?: (files: FileList | File[]) => Promise<ImportedFontAsset[]>;
  showRemove: boolean;
  onSetText: (value: string, fieldKey?: string) => void;
  onSetTextFieldStyle: (fieldKey: string, property: string, value: string) => void;
  onRemoveTextField: (fieldKey: string) => void;
}) {
  return (
    <div className="space-y-3">
      <div className={showRemove ? "flex min-w-0 items-center justify-between gap-2" : "min-w-0"}>
        <div className="min-w-0">
          <div className="truncate text-[11px] font-medium text-neutral-100">
            {formatTextFieldPreview(field.value) || "Text"}
          </div>
          <div className="text-[10px] text-neutral-500">{field.tagName}</div>
        </div>
        {showRemove && (
          <button
            type="button"
            onClick={() => onRemoveTextField(field.key)}
            className="inline-flex h-7 flex-shrink-0 items-center rounded-lg border border-neutral-700 bg-neutral-950 px-2.5 text-[11px] font-medium text-neutral-300 transition-colors hover:border-neutral-600 hover:text-white"
          >
            Remove
          </button>
        )}
      </div>
      <PromotableControl channel={{ kind: "text" }} enabled={field.source === "self"}>
        {({ value, onCommit }) => (
          <TextAreaField
            key={field.key}
            label="Content"
            value={value ?? field.value}
            disabled={false}
            autoFocus={showRemove}
            onCommit={onCommit ?? ((next) => onSetText(next, field.key))}
          />
        )}
      </PromotableControl>
      <PromotableControl
        channel={{ kind: "style", prop: "color" }}
        enabled={field.source === "self"}
      >
        {({ value, onCommit }) => (
          <ColorField
            label="Text color"
            value={value ?? getTextFieldColor(field, styles)}
            disabled={false}
            onCommit={onCommit ?? ((next) => onSetTextFieldStyle(field.key, "color", next))}
          />
        )}
      </PromotableControl>
      <div className={RESPONSIVE_GRID}>
        <MetricField
          label="Size"
          value={field.computedStyles["font-size"] || styles["font-size"] || "16px"}
          disabled={false}
          liveCommit
          onCommit={(next) => onSetTextFieldStyle(field.key, "font-size", next)}
        />
        <FontWeightField
          value={field.computedStyles["font-weight"] || styles["font-weight"] || "400"}
          fontFamily={field.computedStyles["font-family"] || styles["font-family"]}
          disabled={false}
          onCommit={(next) => onSetTextFieldStyle(field.key, "font-weight", next)}
        />
      </div>
      <PromotableControl
        channel={{ kind: "style", prop: "font-family" }}
        enabled={field.source === "self"}
      >
        {({ value, onCommit }) => (
          <FontFamilyField
            value={
              value ?? (field.computedStyles["font-family"] || styles["font-family"] || "inherit")
            }
            disabled={false}
            importedFonts={fontAssets}
            onImportFonts={onImportFonts}
            onCommit={onCommit ?? ((next) => onSetTextFieldStyle(field.key, "font-family", next))}
          />
        )}
      </PromotableControl>
      <AdvancedTextControls
        field={field}
        inheritedStyles={styles}
        disabled={false}
        onCommit={(property, value) => onSetTextFieldStyle(field.key, property, value)}
      />
    </div>
  );
}

export function TextSection({
  element,
  styles,
  fontAssets,
  onImportFonts,
  onSetText,
  onSetTextFieldStyle,
  onAddTextField,
  onRemoveTextField,
}: {
  element: DomEditSelection;
  styles: Record<string, string>;
  fontAssets: ImportedFontAsset[];
  onImportFonts?: (files: FileList | File[]) => Promise<ImportedFontAsset[]>;
  onSetText: (value: string, fieldKey?: string) => void;
  onSetTextFieldStyle: (fieldKey: string, property: string, value: string) => void;
  onAddTextField: (afterFieldKey?: string) => string | Promise<string | null> | null;
  onRemoveTextField: (fieldKey: string) => void;
}) {
  const hasTextControls = isTextEditableSelection(element);
  const [activeTextFieldKey, setActiveTextFieldKey] = useState<string | null>(
    element.textFields[0]?.key ?? null,
  );

  useEffect(() => {
    const nextFields = element.textFields;
    setActiveTextFieldKey((current) => {
      if (current && nextFields.some((field) => field.key === current)) return current;
      return nextFields[0]?.key ?? null;
    });
  }, [element.id, element.selector, element.textFields]);

  if (!hasTextControls) return null;

  const textFields = element.textFields;
  const activeField = textFields.find((field) => field.key === activeTextFieldKey) ?? textFields[0];
  if (!activeField) return null;

  if (textFields.length === 1) {
    return (
      <Section title="Text" icon={<Type size={15} />} defaultCollapsed>
        <TextFieldEditor
          field={activeField}
          styles={styles}
          fontAssets={fontAssets}
          onImportFonts={onImportFonts}
          showRemove={false}
          onSetText={onSetText}
          onSetTextFieldStyle={onSetTextFieldStyle}
          onRemoveTextField={onRemoveTextField}
        />
      </Section>
    );
  }

  return (
    <Section title="Text" icon={<Type size={15} />}>
      <div className="space-y-4">
        <div className="grid gap-1.5">
          <div className="flex min-w-0 flex-wrap items-center justify-between gap-2">
            <span className={LABEL}>Text layers</span>
            <button
              type="button"
              onClick={() => {
                void Promise.resolve(onAddTextField(activeField.key)).then((nextKey) => {
                  if (nextKey) setActiveTextFieldKey(nextKey);
                });
              }}
              className="inline-flex h-7 max-w-full items-center gap-1.5 rounded-lg border border-neutral-700 bg-neutral-950 px-2.5 text-[11px] font-medium text-neutral-300 transition-colors hover:border-neutral-600 hover:text-white"
            >
              <Plus size={12} className="flex-shrink-0" />
              <span className="truncate">Add text</span>
            </button>
          </div>
          <div className="grid gap-2">
            {textFields.map((field, index) => {
              const active = field.key === activeField.key;
              return (
                <button
                  key={field.key}
                  type="button"
                  onClick={() => setActiveTextFieldKey(field.key)}
                  className={`min-w-0 w-full rounded-xl border px-3 py-2 text-left transition-colors ${
                    active
                      ? "border-studio-accent/50 bg-studio-accent/10"
                      : "border-neutral-800 bg-neutral-900/80 hover:border-neutral-700 hover:bg-neutral-900"
                  }`}
                >
                  <div className="flex min-w-0 items-center justify-between gap-2">
                    <div className="flex min-w-0 items-center gap-2">
                      <span
                        className="h-4 w-4 flex-shrink-0 rounded border border-neutral-700 bg-neutral-950"
                        style={{ backgroundColor: getTextFieldColor(field, styles) }}
                      />
                      <span className="min-w-0 truncate text-[11px] font-medium text-neutral-100">
                        {formatTextFieldPreview(field.value) || `Text ${index + 1}`}
                      </span>
                    </div>
                    <span className="flex-shrink-0 rounded-md border border-neutral-700 bg-neutral-950 px-1.5 py-0.5 text-[10px] text-neutral-500">
                      {field.tagName}
                    </span>
                  </div>
                </button>
              );
            })}
          </div>
        </div>
        <TextFieldEditor
          field={activeField}
          styles={styles}
          fontAssets={fontAssets}
          onImportFonts={onImportFonts}
          showRemove={true}
          onSetText={onSetText}
          onSetTextFieldStyle={onSetTextFieldStyle}
          onRemoveTextField={onRemoveTextField}
        />
      </div>
    </Section>
  );
}

export { StyleSections } from "./propertyPanelStyleSections";
