import { Button, ConfirmDialog, Tooltip } from '@cherrystudio/ui'
import { cn } from '@cherrystudio/ui/lib/utils'
import { Loader2, Plus, Trash2 } from 'lucide-react'
import type { FC, UIEventHandler } from 'react'
import { useEffect, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'

import type { PaintingStripEntry } from '../hooks/usePaintingHistory'
import type { PaintingData } from '../model/types/paintingData'
import { paintingClasses } from '../paintingPrimitives'
import { getPaintingFileUrl } from '../utils/paintingFileUrl'

interface PaintingStripProps {
  selectedPaintingId?: string
  /** Id of the painting with an in-flight generation, or undefined when idle. */
  runningPaintingId?: string
  items: PaintingStripEntry[]
  hasMore: boolean
  loadMore: () => void
  onDeletePainting: (painting: PaintingData) => void
  onSelectPainting: (painting: PaintingData) => void
  onAddPainting: () => void
}

const PaintingStripItem: FC<{
  painting: PaintingStripEntry
  selected: boolean
  loading: boolean
  onDelete: (painting: PaintingStripEntry) => void
  onSelect: (painting: PaintingStripEntry) => void
  selectLabel: string
  deleteLabel: string
}> = ({ painting, selected, loading, onDelete, onSelect, selectLabel, deleteLabel }) => {
  const previewFile = painting.files?.[0]
  const previewUrl = previewFile ? getPaintingFileUrl(previewFile) : undefined

  return (
    <div className={cn(paintingClasses.historyItem, selected && paintingClasses.historyItemActive)}>
      <button
        type="button"
        className="absolute inset-0 z-0"
        aria-label={selectLabel}
        onClick={() => onSelect(painting)}>
        <span className="pointer-events-none absolute inset-0 overflow-hidden rounded-[12px]">
          {previewUrl ? (
            <img src={previewUrl} alt="" className="h-full w-full object-cover" />
          ) : loading ? (
            <span className="flex h-full w-full items-center justify-center bg-muted/60">
              <Loader2 className="size-4 animate-spin text-muted-foreground/70" />
            </span>
          ) : (
            <span className="block size-full bg-muted/60" aria-hidden />
          )}
        </span>
      </button>

      {selected && (
        <span
          aria-hidden
          className="pointer-events-none absolute inset-0 z-10 rounded-[12px] ring-2 ring-muted-foreground/55 ring-inset"
        />
      )}

      {loading && previewFile && (
        <span className="pointer-events-none absolute inset-x-1 bottom-1 z-10 h-1 overflow-hidden rounded-full bg-black/10">
          <span className="block h-full w-5 animate-[painting-history-loading_1.2s_ease-in-out_infinite] rounded-full bg-foreground/70" />
        </span>
      )}

      <button
        type="button"
        aria-label={deleteLabel}
        className={paintingClasses.historyDelete}
        onClick={(event) => {
          event.stopPropagation()
          onDelete(painting)
        }}>
        <Trash2 className="size-3" />
      </button>
    </div>
  )
}

const PaintingStrip: FC<PaintingStripProps> = ({
  selectedPaintingId,
  runningPaintingId,
  items,
  hasMore,
  loadMore,
  onDeletePainting,
  onSelectPainting,
  onAddPainting
}) => {
  const { t } = useTranslation()
  const [pendingDelete, setPendingDelete] = useState<PaintingStripEntry | null>(null)
  const stripRef = useRef<HTMLDivElement>(null)
  const handleScroll: UIEventHandler<HTMLDivElement> = (event) => {
    const target = event.currentTarget
    if (target.scrollTop + target.clientHeight >= target.scrollHeight - 120) {
      loadMore()
    }
  }

  useEffect(() => {
    const strip = stripRef.current
    if (hasMore && strip && strip.scrollHeight <= strip.clientHeight) {
      loadMore()
    }
  }, [hasMore, items.length, loadMore])

  return (
    <>
      <div ref={stripRef} className={paintingClasses.historyStrip} onScroll={handleScroll}>
        <Tooltip content={t('paintings.button.new.image')} placement="right" delay={500}>
          <Button
            type="button"
            variant="ghost"
            size="icon-sm"
            className={paintingClasses.historyAddButton}
            aria-label={t('paintings.button.new.image')}
            onClick={onAddPainting}>
            <Plus className="size-4" />
          </Button>
        </Tooltip>
        {items.map((painting) => (
          <PaintingStripItem
            key={painting.id}
            painting={painting}
            selected={painting.id === selectedPaintingId}
            loading={painting.id === runningPaintingId}
            onDelete={setPendingDelete}
            onSelect={onSelectPainting}
            selectLabel={t('paintings.button.select.image')}
            deleteLabel={t('paintings.button.delete.image.label')}
          />
        ))}
        {hasMore && <Loader2 className="mx-auto size-4 shrink-0 animate-spin text-muted-foreground/60" aria-hidden />}
      </div>

      <style>{`
        @keyframes painting-history-loading {
          0% { transform: translateX(-150%); }
          100% { transform: translateX(260%); }
        }
      `}</style>

      <ConfirmDialog
        open={Boolean(pendingDelete)}
        onOpenChange={(open) => {
          if (!open) {
            setPendingDelete(null)
          }
        }}
        title={t('paintings.button.delete.image.confirm')}
        confirmText={t('common.delete')}
        cancelText={t('common.cancel')}
        destructive
        onConfirm={() => {
          if (pendingDelete) {
            onDeletePainting(pendingDelete)
          }
          setPendingDelete(null)
        }}
      />
    </>
  )
}

export default PaintingStrip
