import { useEffect, useState, type Dispatch, type SetStateAction } from "react";
import { BoundingBox } from "@phosphor-icons/react";
import { commandIds } from "@commands/ids";
import type { Rect } from "@core/geometry";
import type { AppStore } from "@editor/store";
import type { TransformTarget } from "@editor/transform";
import { BottomControlDivider } from "./Divider";
import { bottomControlIconSlotClass, bottomControlInputClass, bottomControlLabelClass } from "./styles";

export type TransformControlsProps = {
  bounds: Rect;
  target: TransformTarget;
  dispatch: AppStore["dispatch"];
};

type BoundsField = keyof Rect;

export function TransformControls({ bounds, target, dispatch }: TransformControlsProps) {
  const [draft, setDraft] = useState(() => draftFromBounds(bounds));

  useEffect(() => {
    setDraft(draftFromBounds(bounds));
  }, [bounds.x, bounds.y, bounds.w, bounds.h]);

  const commitField = (field: BoundsField) => {
    const value = Number.parseFloat(draft[field]);
    if (!Number.isFinite(value)) {
      setDraft(draftFromBounds(bounds));
      return;
    }

    dispatch(commandIds.transformSetBounds, {
      target,
      bounds: {
        ...bounds,
        [field]: field === "w" || field === "h" ? Math.max(1, value) : value,
      },
    });
  };

  return (
    <div className="flex w-full items-center justify-center gap-2 tabular-nums">
      <span className={bottomControlIconSlotClass()}>
        <BoundingBox size={16} weight="regular" />
      </span>
      <BottomControlDivider />
      <BoundsInput label="X" field="x" draft={draft.x} setDraft={setDraft} commitField={commitField} />
      <BoundsInput label="Y" field="y" draft={draft.y} setDraft={setDraft} commitField={commitField} />
      <BottomControlDivider />
      <BoundsInput label="W" field="w" draft={draft.w} setDraft={setDraft} commitField={commitField} />
      <BoundsInput label="H" field="h" draft={draft.h} setDraft={setDraft} commitField={commitField} />
    </div>
  );
}

function BoundsInput({
  label,
  field,
  draft,
  setDraft,
  commitField,
}: {
  label: string;
  field: BoundsField;
  draft: string;
  setDraft: Dispatch<SetStateAction<Record<BoundsField, string>>>;
  commitField: (field: BoundsField) => void;
}) {
  return (
    <label className="flex items-center gap-1">
      <span className={bottomControlLabelClass()}>{label}</span>
      <input
        className={bottomControlInputClass()}
        inputMode="decimal"
        value={draft}
        aria-label={label}
        onChange={(event) => setDraft((current) => ({ ...current, [field]: event.target.value }))}
        onBlur={() => commitField(field)}
        onFocus={(event) => event.currentTarget.select()}
        onKeyDown={(event) => {
          event.stopPropagation();
          if (event.key === "Enter") {
            commitField(field);
            event.currentTarget.blur();
          }
          if (event.key === "Escape") event.currentTarget.blur();
        }}
      />
    </label>
  );
}

function draftFromBounds(bounds: Rect): Record<BoundsField, string> {
  return {
    x: String(Math.round(bounds.x)),
    y: String(Math.round(bounds.y)),
    w: String(Math.round(bounds.w)),
    h: String(Math.round(bounds.h)),
  };
}
