'use client';

import { useRef, useState } from 'react';

type Box = { xPct: number; yPct: number; wPct: number; hPct: number }; // 0-100

const DEFAULT_BOX: Box = { xPct: 30, yPct: 25, wPct: 40, hPct: 35 };
const MIN_SIZE = 6; // percent

export default function PhotoPrintAreaField({ variant = 'front' }: { variant?: 'front' | 'back' }) {
  const [previewUrl, setPreviewUrl] = useState<string | null>(null);
  const [box, setBox] = useState<Box>(DEFAULT_BOX);
  const containerRef = useRef<HTMLDivElement>(null);
  const dragState = useRef<{
    mode: 'move' | 'resize';
    startX: number;
    startY: number;
    startBox: Box;
  } | null>(null);

  const fieldName = variant === 'front' ? 'image' : 'imageBack';
  const suffix = variant === 'front' ? '' : 'Back';

  const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const file = e.target.files?.[0];
    if (!file) {
      setPreviewUrl(null);
      return;
    }
    setPreviewUrl(URL.createObjectURL(file));
    setBox(DEFAULT_BOX);
  };

  const onBoxMouseDown = (e: React.MouseEvent) => {
    e.preventDefault();
    dragState.current = { mode: 'move', startX: e.clientX, startY: e.clientY, startBox: box };
    window.addEventListener('mousemove', onMouseMove);
    window.addEventListener('mouseup', onMouseUp);
  };

  const onResizeMouseDown = (e: React.MouseEvent) => {
    e.preventDefault();
    e.stopPropagation();
    dragState.current = { mode: 'resize', startX: e.clientX, startY: e.clientY, startBox: box };
    window.addEventListener('mousemove', onMouseMove);
    window.addEventListener('mouseup', onMouseUp);
  };

  const onMouseMove = (e: MouseEvent) => {
    const state = dragState.current;
    const rect = containerRef.current?.getBoundingClientRect();
    if (!state || !rect) return;

    const dxPct = ((e.clientX - state.startX) / rect.width) * 100;
    const dyPct = ((e.clientY - state.startY) / rect.height) * 100;

    if (state.mode === 'move') {
      const xPct = clamp(state.startBox.xPct + dxPct, 0, 100 - state.startBox.wPct);
      const yPct = clamp(state.startBox.yPct + dyPct, 0, 100 - state.startBox.hPct);
      setBox({ ...state.startBox, xPct, yPct });
    } else {
      const wPct = clamp(state.startBox.wPct + dxPct, MIN_SIZE, 100 - state.startBox.xPct);
      const hPct = clamp(state.startBox.hPct + dyPct, MIN_SIZE, 100 - state.startBox.yPct);
      setBox({ ...state.startBox, wPct, hPct });
    }
  };

  const onMouseUp = () => {
    dragState.current = null;
    window.removeEventListener('mousemove', onMouseMove);
    window.removeEventListener('mouseup', onMouseUp);
  };

  return (
    <div>
      <input
        id={fieldName}
        name={fieldName}
        type="file"
        accept="image/*"
        onChange={handleFileChange}
        className="w-full border border-line bg-paper px-3 py-2 text-sm"
      />
      {variant === 'front' ? (
        <p className="mt-1 text-xs text-muted">
          Uploading a real photo replaces the illustration everywhere this product is shown. One
          tradeoff: the color swatches below can no longer recolor a photo the way they recolor the
          illustration — they&apos;ll still be saved with each order, but the picture itself stays
          fixed. Leave this blank to keep using the illustration (which does recolor live).
        </p>
      ) : (
        <p className="mt-1 text-xs text-muted">
          If set, customers get a Front/Back toggle and can add a separate design to the back —
          drag a print-area box below just like the front.
        </p>
      )}

      {previewUrl && (
        <div className="mt-4">
          <p className="tag-label mb-2">Drag the box to mark the print area</p>
          <p className="mb-2 text-xs text-muted">
            Cropped to a square here — that&apos;s the same crop the design tool uses, so the box
            lines up correctly.
          </p>
          <div
            ref={containerRef}
            className="relative aspect-square w-full max-w-sm select-none border border-line"
            style={{ touchAction: 'none' }}
          >
            {/* eslint-disable-next-line @next/next/no-img-element */}
            <img
              src={previewUrl}
              alt="Product preview"
              className="absolute inset-0 h-full w-full object-cover"
              draggable={false}
            />
            <div
              onMouseDown={onBoxMouseDown}
              className="absolute cursor-move border-2 border-dashed bg-splash-pink/10"
              style={{
                left: `${box.xPct}%`,
                top: `${box.yPct}%`,
                width: `${box.wPct}%`,
                height: `${box.hPct}%`,
                borderColor: '#E5227E',
              }}
            >
              <div
                onMouseDown={onResizeMouseDown}
                className="absolute -bottom-1.5 -right-1.5 h-4 w-4 cursor-se-resize rounded-full border border-paper bg-splash-pink"
              />
            </div>
          </div>
          <p className="mt-1 text-xs text-muted">Drag the pink handle to resize.</p>
        </div>
      )}

      <input type="hidden" name={`hasCustomPrintArea${suffix}`} value={previewUrl ? '1' : ''} />
      <input type="hidden" name={`printX${suffix}`} value={box.xPct / 100} />
      <input type="hidden" name={`printY${suffix}`} value={box.yPct / 100} />
      <input type="hidden" name={`printW${suffix}`} value={box.wPct / 100} />
      <input type="hidden" name={`printH${suffix}`} value={box.hPct / 100} />
    </div>
  );
}

function clamp(n: number, min: number, max: number) {
  return Math.min(Math.max(n, min), Math.max(min, max));
}
