import {
  Star,
  X,
  ArrowDown,
  ArrowUp,
  PanelLeftOpen,
  PanelLeftClose,
  PanelRightOpen,
  PanelRightClose,
} from 'lucide-react'
import { cn } from '@/lib/utils'
import {
  useFilterStore,
  hasActiveFilters,
  type MediaType,
  type SortField,
} from '../../store/filterStore'
import {
  useViewSettingsStore,
  THUMBNAIL_SIZE_PRESETS,
  DEFAULT_THUMBNAIL_SIZE,
  type ThumbnailSizeLevel,
} from '../../store/viewSettingsStore'
import { useTagsQuery } from '../../hooks/useTagsQuery'
import { FilterPill } from './FilterPill'
import { COLOR_LABEL_OPTIONS } from '../../constants/colorLabels'
import { Button } from '@/components/ui/button'
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '@/components/ui/select'
import { MultiSelect } from '@/components/ui/multi-select'

const MEDIA_TYPES: { value: MediaType; label: string }[] = [
  { value: 'photo', label: 'Photo' },
  { value: 'video', label: 'Video' },
  { value: 'raw', label: 'RAW' },
  { value: 'heic', label: 'HEIC' },
]

const SORT_OPTIONS: { value: SortField; label: string }[] = [
  { value: 'taken_at', label: 'Date taken' },
  { value: 'added_at', label: 'Date added' },
  { value: 'filename', label: 'Filename' },
  { value: 'file_size', label: 'File size' },
  { value: 'rating', label: 'Rating' },
]

// Short labels for each thumbnail preset in THUMBNAIL_SIZE_PRESETS order.
// Used by the Size pill's value summary AND the buttons inside its
// popover, so the two stay in sync.
const SIZE_LABELS = ['XS', 'S', 'M', 'L', 'XL'] as const

/**
 * Compact, always-visible filter toolbar built out of FilterPill primitives.
 * Each pill represents a filter category, opens a popover with the
 * underlying control, and shows a short value summary inline when active.
 * Replaces the old expandable FilterBar + ActiveFilterChips combo.
 */
interface FilterBarProps {
  leftSidebarOpen: boolean
  rightSidebarOpen: boolean
  onToggleLeftSidebar: () => void
  onToggleRightSidebar: () => void
}

export function FilterBar({
  leftSidebarOpen,
  rightSidebarOpen,
  onToggleLeftSidebar,
  onToggleRightSidebar,
}: FilterBarProps) {
  const filterState = useFilterStore()
  const mediaTypes = useFilterStore((s) => s.mediaTypes)
  const ratingMin = useFilterStore((s) => s.ratingMin)
  const colorLabel = useFilterStore((s) => s.colorLabel)
  const flag = useFilterStore((s) => s.flag)
  const sortBy = useFilterStore((s) => s.sortBy)
  const sortOrder = useFilterStore((s) => s.sortOrder)
  const tagIds = useFilterStore((s) => s.tagIds)
  const dateFrom = useFilterStore((s) => s.dateFrom)
  const dateTo = useFilterStore((s) => s.dateTo)
  const setDateFrom = useFilterStore((s) => s.setDateFrom)
  const setDateTo = useFilterStore((s) => s.setDateTo)
  const currentSection = useFilterStore((s) => s.currentSection)

  // Only the Flag pill is hidden inside the Discarded section. Flag has
  // exactly two values and the section locks one of them, so the pill
  // would only ever toggle the section off — useless. Rating + Tags
  // pills stay visible in their sections because the user can refine
  // them further (ratingMin >= 3, restrict to specific tag ids).
  const hideFlagPill = currentSection === 'discarded'

  const toggleMediaType = useFilterStore((s) => s.toggleMediaType)
  const setRatingMin = useFilterStore((s) => s.setRatingMin)
  const setColorLabel = useFilterStore((s) => s.setColorLabel)
  const setFlag = useFilterStore((s) => s.setFlag)
  const setTagIds = useFilterStore((s) => s.setTagIds)
  const setSortBy = useFilterStore((s) => s.setSortBy)
  const toggleSortOrder = useFilterStore((s) => s.toggleSortOrder)
  const clearAll = useFilterStore((s) => s.clearAll)

  const { data: allTags = [] } = useTagsQuery()

  // Pre-compute pill values + active flags so the JSX stays terse.
  const typeActive = mediaTypes.length > 0
  const typeValue = typeActive
    ? mediaTypes.map((t) => t.toUpperCase()).join(', ')
    : null

  const ratingActive = ratingMin > 0
  const ratingValue = ratingActive ? `≥ ${ratingMin}★` : null

  const colorActive = colorLabel !== null
  const colorValue = colorActive ? colorLabel : null

  const flagActive = flag !== 'any'
  const flagValue = flagActive
    ? flag === 'date_warning'
      ? 'date issues'
      : flag
    : null

  const tagActive = tagIds.length > 0
  const activeTagNames = allTags
    .filter((t) => tagIds.includes(t.id))
    .map((t) => t.name)
  const tagValue = tagActive
    ? activeTagNames.length <= 2
      ? activeTagNames.join(', ')
      : `${activeTagNames.slice(0, 2).join(', ')} +${activeTagNames.length - 2}`
    : null

  const sortLabel = SORT_OPTIONS.find((o) => o.value === sortBy)?.label ?? sortBy
  const sortValue = `${sortLabel} ${sortOrder === 'desc' ? '↓' : '↑'}`

  const thumbnailSize = useViewSettingsStore((s) => s.thumbnailSize)
  const setThumbnailSize = useViewSettingsStore((s) => s.setThumbnailSize)
  const sizeIdx = THUMBNAIL_SIZE_PRESETS.indexOf(thumbnailSize)
  const sizeValue = `${SIZE_LABELS[sizeIdx] ?? '–'} (${thumbnailSize}px)`

  const anyActive = hasActiveFilters(filterState)

  return (
    <div className="flex h-9 items-center gap-3 border-b border-border bg-surface px-3 py-0">
      {/* Left sidebar toggle — pinned to the far-left edge of the bar so it
       *  sits flush against the panel it controls (or the viewport edge
       *  when collapsed). */}
      <button
        onClick={onToggleLeftSidebar}
        className="flex-shrink-0 rounded p-1 text-text-muted hover:bg-surface-2 hover:text-text"
        title={leftSidebarOpen ? 'Collapse panel (Tab)' : 'Expand panel (Tab)'}
        aria-label={leftSidebarOpen ? 'Collapse left panel' : 'Expand left panel'}
      >
        {leftSidebarOpen ? (
          <PanelLeftClose className="h-3.5 w-3.5" />
        ) : (
          <PanelLeftOpen className="h-3.5 w-3.5" />
        )}
      </button>

      {/* Pills — left side, scroll horizontally if they overflow. */}
      <div className="flex min-w-0 flex-1 items-center gap-1.5 overflow-x-auto">
        {/* Date */}
        <FilterPill
          label="Date"
          value={
            dateFrom || dateTo
              ? dateFrom && dateTo && dateFrom === dateTo
                ? dateFrom
                : `${dateFrom ?? '…'} → ${dateTo ?? '…'}`
              : null
          }
          isActive={dateFrom !== null || dateTo !== null}
          onClear={() => {
            setDateFrom(null)
            setDateTo(null)
          }}
          contentClassName="w-56 space-y-2 p-3"
        >
          <label className="block space-y-0.5">
            <span className="text-[10px] uppercase tracking-wider text-text-muted">
              From
            </span>
            <input
              type="date"
              value={dateFrom ?? ''}
              onChange={(e) => setDateFrom(e.target.value || null)}
              max={dateTo ?? undefined}
              className="w-full rounded border border-border bg-bg px-2 py-1 text-xs text-text"
            />
          </label>
          <label className="block space-y-0.5">
            <span className="text-[10px] uppercase tracking-wider text-text-muted">
              To
            </span>
            <input
              type="date"
              value={dateTo ?? ''}
              onChange={(e) => setDateTo(e.target.value || null)}
              min={dateFrom ?? undefined}
              className="w-full rounded border border-border bg-bg px-2 py-1 text-xs text-text"
            />
          </label>
        </FilterPill>

        {/* Type */}
        <FilterPill
          label="Type"
          value={typeValue}
          isActive={typeActive}
          onClear={() => mediaTypes.forEach((t) => toggleMediaType(t))}
        >
          <MultiSelect
            searchable={false}
            pinSelected={false}
            options={MEDIA_TYPES.map(({ value, label }) => ({
              value,
              label,
            }))}
            values={mediaTypes}
            onChange={(next) => {
              // Diff against current selection — store uses per-item toggles.
              for (const t of MEDIA_TYPES.map((m) => m.value)) {
                const wasOn = mediaTypes.includes(t)
                const nowOn = next.includes(t as MediaType)
                if (wasOn !== nowOn) toggleMediaType(t)
              }
            }}
          />
        </FilterPill>

        {/* Rating */}
        <FilterPill
          label="Rating"
          value={ratingValue}
          isActive={ratingActive}
          onClear={() => setRatingMin(0)}
        >
          <div>
            <p className="mb-1 text-[11px] text-text-muted">Minimum</p>
            <div className="flex gap-1">
              {[1, 2, 3, 4, 5].map((n) => (
                <button
                  key={n}
                  onClick={() => setRatingMin(ratingMin === n ? 0 : n)}
                  className="p-0.5"
                  title={`At least ${n} star${n > 1 ? 's' : ''}`}
                >
                  <Star
                    className={cn(
                      'h-5 w-5 transition-colors',
                      n <= ratingMin
                        ? 'fill-star text-star'
                        : 'text-text-muted hover:text-star'
                    )}
                  />
                </button>
              ))}
            </div>
          </div>
        </FilterPill>

        {/* Color */}
        <FilterPill
          label="Color"
          value={colorValue}
          isActive={colorActive}
          onClear={() => setColorLabel(null)}
        >
          <div className="flex items-center gap-1.5">
            {COLOR_LABEL_OPTIONS.map(({ value, className }) => {
              const active = colorLabel === value
              return (
                <button
                  key={value}
                  onClick={() => setColorLabel(active ? null : value)}
                  className={cn(
                    'h-5 w-5 rounded-full ring-offset-2 ring-offset-surface transition-all',
                    className,
                    active ? 'ring-2 ring-primary' : 'opacity-60 hover:opacity-100'
                  )}
                  title={value}
                />
              )
            })}
            {colorLabel && (
              <button
                onClick={() => setColorLabel(null)}
                className="ml-1 rounded p-0.5 text-text-muted hover:bg-surface-2 hover:text-text"
                title="Clear color"
              >
                <X className="h-3 w-3" />
              </button>
            )}
          </div>
        </FilterPill>

        {/* Flag — hidden in the Discarded section, where the flag is
       *  pinned to "discarded" by the section preset. */}
        {!hideFlagPill && (
          <FilterPill
            label="Flag"
            value={flagValue}
            isActive={flagActive}
            onClear={() => setFlag('any')}
            >
            <MultiSelect
              searchable={false}
              pinSelected={false}
              options={[
                { value: 'discarded', label: 'Discarded' },
                { value: 'date_warning', label: 'Date issues' },
              ]}
              values={flag !== 'any' ? [flag] : []}
              onChange={(next) => {
                // Flag state is mutually exclusive in the store; treat
                // the just-added value as the new single selection.
                const added = next.find((v) => v !== (flag !== 'any' ? flag : ''))
                if (!added) {
                  setFlag('any')
                  return
                }
                setFlag(added as 'discarded' | 'date_warning')
              }}
              />
          </FilterPill>
        )}

        {/* Tags */}
        {allTags.length > 0 && (
          <FilterPill
            label="Tags"
            value={tagValue}
            isActive={tagActive}
            onClear={() => setTagIds([])}
            >
            <MultiSelect
              className="w-60"
              searchPlaceholder="Search tags…"
              emptyMessage="No tags match"
              options={allTags
                .slice()
                .sort((a, b) => {
                  if (b.photo_count !== a.photo_count)
                    return b.photo_count - a.photo_count
                  return a.name.localeCompare(b.name)
                })
                .map((t) => ({
                  value: t.id,
                  label: t.name,
                  meta: t.photo_count,
                }))}
              values={tagIds}
              onChange={setTagIds}
            />
          </FilterPill>
        )}

        {/* Sort — always present, never "active/inactive" since there's
          always a value. */}
        <FilterPill label="Sort" value={sortValue} isActive>
          <div className="space-y-2">
            <Select
              value={sortBy}
              onValueChange={(v) => setSortBy(v as SortField)}
            >
              <SelectTrigger>
                <SelectValue />
              </SelectTrigger>
              <SelectContent>
                {SORT_OPTIONS.map((opt) => (
                  <SelectItem key={opt.value} value={opt.value}>
                    {opt.label}
                  </SelectItem>
                ))}
              </SelectContent>
            </Select>
            <Button
              variant="secondary"
              size="sm"
              onClick={toggleSortOrder}
              className="w-full"
            >
              {sortOrder === 'desc' ? (
                <>
                  <ArrowDown className="h-3.5 w-3.5" />
                  Descending
                </>
              ) : (
                <>
                  <ArrowUp className="h-3.5 w-3.5" />
                  Ascending
                </>
              )}
            </Button>
          </div>
        </FilterPill>

        {/* Size — controls the thumbnail cell size in the Timeline,
         *  Memories, Duplicates, and other grid views. Doesn't apply to
         *  the preview filmstrip (which has its own fixed track size).
         *  Marked isActive so the pill always reads as "in effect",
         *  matching Sort's treatment. */}
        <FilterPill
          label="Size"
          value={sizeValue}
          isActive
          onClear={
            thumbnailSize === DEFAULT_THUMBNAIL_SIZE
              ? undefined
              : () => setThumbnailSize(DEFAULT_THUMBNAIL_SIZE)
          }
        >
          <div className="space-y-2 p-1">
            <div className="text-[10px] uppercase tracking-wider text-text-muted">
              Thumbnail size
            </div>
            <div className="flex items-center gap-1.5">
              {THUMBNAIL_SIZE_PRESETS.map((preset, idx) => {
                const selected = preset === thumbnailSize
                // Visual chip — a square that grows with the preset so
                // the user can see the relative scaling without reading
                // the px number. Capped at 28px so the popover stays
                // narrow even at the XL preset.
                const swatch = 12 + idx * 4
                return (
                  <button
                    key={preset}
                    type="button"
                    onClick={() =>
                      setThumbnailSize(preset as ThumbnailSizeLevel)
                    }
                    className={cn(
                      'flex h-10 w-10 flex-col items-center justify-center gap-0.5 rounded border text-[10px] transition-colors',
                      selected
                        ? 'border-primary/60 bg-primary/15 text-primary'
                        : 'border-border bg-surface-2 text-text-muted hover:bg-surface-offset hover:text-text'
                    )}
                    title={`${SIZE_LABELS[idx]} — ${preset}px`}
                    aria-pressed={selected}
                  >
                    <span
                      className={cn(
                        'rounded-sm',
                        selected ? 'bg-primary' : 'bg-text-muted/50'
                      )}
                      style={{ width: swatch, height: swatch }}
                    />
                    <span className="leading-none">{SIZE_LABELS[idx]}</span>
                  </button>
                )
              })}
            </div>
          </div>
        </FilterPill>

        {/* Clear-all — borderless text affordance pinned next to the pill
       *  cluster on the right. Lives inside the pills container so it
       *  shares the same flex group and gap and reads as "another
       *  pill". Only renders when any filter is active. */}
        {anyActive && (
          <button
            onClick={clearAll}
            className="ml-1 flex h-7 flex-shrink-0 items-center whitespace-nowrap px-1 text-xs text-text-muted underline-offset-2 hover:text-text hover:underline"
            title="Clear all filters in this section"
          >
            Clear all
          </button>
        )}
      </div>

      {/* Right sidebar toggle — pinned to the far-right edge. */}
      <button
        onClick={onToggleRightSidebar}
        className="flex-shrink-0 rounded p-1 text-text-muted hover:bg-surface-2 hover:text-text"
        title={rightSidebarOpen ? 'Collapse panel (I)' : 'Expand panel (I)'}
        aria-label={rightSidebarOpen ? 'Collapse right panel' : 'Expand right panel'}
      >
        {rightSidebarOpen ? (
          <PanelRightClose className="h-3.5 w-3.5" />
        ) : (
          <PanelRightOpen className="h-3.5 w-3.5" />
        )}
      </button>
    </div>
  )
}

