// @design-system: domain/DealImageManager

'use client';

import * as React from 'react';
import { Star, X } from 'lucide-react';
import { ImageUploadField } from '@/components/ui/primitives/ImageUploadField/ImageUploadField';
import { useT } from '@/lib/i18n/react';

export type DealImageEntryUI = {
  r2Key: string;
  isPrimary: boolean;
  sortOrder: number;
};

export type DealImageManagerProps = {
  value: DealImageEntryUI[];
  onChange: (next: DealImageEntryUI[]) => void;
  max: number;
  /** When true, blocks removing the last image. Default true. */
  mandatoryOne?: boolean;
};

function normalize(entries: DealImageEntryUI[]): DealImageEntryUI[] {
  if (entries.length === 0) return entries;
  const primaryIdx = entries.findIndex((e) => e.isPrimary);
  const resolvedPrimaryIdx = primaryIdx === -1 ? 0 : primaryIdx;
  return entries.map((e, i) => ({
    ...e,
    sortOrder: i,
    isPrimary: i === resolvedPrimaryIdx,
  }));
}

export function DealImageManager({
  value,
  onChange,
  max,
  mandatoryOne = true,
}: DealImageManagerProps) {
  const t = useT('vendor_images');

  // Transient URL state for the add-slot ImageUploadField (always kept null after capture)
  const [addSlotUrl, setAddSlotUrl] = React.useState<string | null>(null);

  const handleUploaded = (r2Key: string) => {
    if (value.length >= max) return;
    const next = normalize([
      ...value,
      { r2Key, isPrimary: value.length === 0, sortOrder: value.length },
    ]);
    onChange(next);
    // Reset the add-slot so it stays as an empty uploader
    setAddSlotUrl(null);
  };

  const handleRemove = (index: number) => {
    if (mandatoryOne && value.length === 1) return;
    const next = value.filter((_, i) => i !== index);
    onChange(normalize(next));
  };

  const handlePrimary = (index: number) => {
    onChange(value.map((e, i) => ({ ...e, isPrimary: i === index })));
  };

  const handleMove = (from: number, to: number) => {
    if (to < 0 || to >= value.length) return;
    const next = [...value];
    const removed = next.splice(from, 1);
    const moved = removed[0];
    if (!moved) return;
    next.splice(to, 0, moved);
    onChange(normalize(next));
  };

  const countLabel = t('count')
    .replace('{{count}}', String(value.length))
    .replace('{{max}}', String(max));

  return (
    <div className="flex flex-col gap-3">
      <div className="flex flex-wrap gap-3">
        {value.map((entry, i) => (
          <div
            key={entry.r2Key}
            className="relative h-24 w-24 overflow-hidden rounded-md border border-[color:var(--border)] bg-[color:var(--surface-2)]"
            data-testid="deal-image-thumb"
          >
            <img
              src={`/r2/${entry.r2Key}`}
              alt=""
              className="h-full w-full object-cover"
              loading="lazy"
            />
            <div className="absolute inset-x-0 bottom-0 flex items-center justify-between bg-[color:var(--surface-overlay)] px-1 py-0.5 text-xs">
              <button
                type="button"
                onClick={() => handlePrimary(i)}
                aria-label={t('setPrimary')}
                aria-pressed={entry.isPrimary}
                className="p-0.5"
              >
                <Star
                  className={`h-3.5 w-3.5 ${
                    entry.isPrimary
                      ? 'fill-[color:var(--brand)] text-[color:var(--brand)]'
                      : 'text-[color:var(--text-muted)]'
                  }`}
                />
              </button>
              <div className="flex gap-0.5">
                <button
                  type="button"
                  onClick={() => handleMove(i, i - 1)}
                  disabled={i === 0}
                  aria-label={t('moveStart')}
                  className="px-1 disabled:opacity-30"
                >
                  <span aria-hidden>‹</span>
                </button>
                <button
                  type="button"
                  onClick={() => handleMove(i, i + 1)}
                  disabled={i === value.length - 1}
                  aria-label={t('moveEnd')}
                  className="px-1 disabled:opacity-30"
                >
                  <span aria-hidden>›</span>
                </button>
              </div>
            </div>
            <button
              type="button"
              onClick={() => handleRemove(i)}
              disabled={mandatoryOne && value.length === 1}
              aria-label={t('remove')}
              title={
                mandatoryOne && value.length === 1
                  ? t('cannotRemoveLast')
                  : t('remove')
              }
              className="absolute end-1 top-1 rounded-full bg-[color:var(--surface)] p-1 disabled:opacity-40"
            >
              <X className="h-3 w-3" />
            </button>
          </div>
        ))}
        {value.length < max && (
          <div className="h-24 w-24">
            <ImageUploadField
              label={t('addImage')}
              value={addSlotUrl}
              onChange={setAddSlotUrl}
              onR2Key={handleUploaded}
              purpose="deal_image"
              aspectRatio="1:1"
            />
          </div>
        )}
      </div>
      <p className="text-xs text-[color:var(--text-muted)]">{countLabel}</p>
    </div>
  );
}
