import { useEffect, useMemo, useRef, useState } from 'react'
import {
  Star,
  X,
  ArrowDown,
  ArrowUp,
  Search,
  AlertTriangle,
  Check,
  PanelLeftOpen,
  PanelLeftClose,
  PanelRightOpen,
  PanelRightClose,
} from 'lucide-react'
import clsx from 'clsx'
import {
  useFilterStore,
  hasActiveFilters,
  type MediaType,
  type SortField,
} from '../../store/filterStore'
import { useTagsQuery } from '../../hooks/useTagsQuery'
import type { Tag } from '../../services/api'
import { FilterPill } from './FilterPill'
import { COLOR_LABEL_OPTIONS } from '../../constants/colorLabels'

const SEARCH_DEBOUNCE_MS = 300

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' },
]

/**
 * 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 dateFrom = useFilterStore((s) => s.dateFrom)
  const dateTo = useFilterStore((s) => s.dateTo)
  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 needsReview = useFilterStore((s) => s.needsReview)
  const setNeedsReview = useFilterStore((s) => s.setNeedsReview)
  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 setDateFrom = useFilterStore((s) => s.setDateFrom)
  const setDateTo = useFilterStore((s) => s.setDateTo)
  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 toggleTagId = useFilterStore((s) => s.toggleTagId)
  const setSortBy = useFilterStore((s) => s.setSortBy)
  const toggleSortOrder = useFilterStore((s) => s.toggleSortOrder)
  const clearAll = useFilterStore((s) => s.clearAll)

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

  // Search box. Local state mirrors the store so typing stays responsive
  // while we debounce store writes (each store write triggers a re-fetch).
  const storeQ = useFilterStore((s) => s.q)
  const setStoreQ = useFilterStore((s) => s.setQ)
  const [searchQuery, setSearchQuery] = useState(storeQ)
  useEffect(() => {
    setSearchQuery(storeQ)
  }, [storeQ])
  const debounceRef = useRef<number | null>(null)
  useEffect(() => {
    if (searchQuery === storeQ) return
    if (debounceRef.current) window.clearTimeout(debounceRef.current)
    debounceRef.current = window.setTimeout(() => {
      setStoreQ(searchQuery)
    }, SEARCH_DEBOUNCE_MS)
    return () => {
      if (debounceRef.current) window.clearTimeout(debounceRef.current)
    }
  }, [searchQuery, storeQ, setStoreQ])

  // Pre-compute pill values + active flags so the JSX stays terse.
  const dateActive = dateFrom !== null || dateTo !== null
  const dateValue = dateActive
    ? `${dateFrom ?? '…'} → ${dateTo ?? '…'}`
    : null

  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' || needsReview
  const flagValue = needsReview
    ? 'needs review'
    : flag !== 'any'
      ? 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 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={dateValue}
          isActive={dateActive}
          onClear={() => {
            setDateFrom(null)
            setDateTo(null)
          }}
        >
          <div className="space-y-2">
            <div>
              <label className="mb-1 block text-[11px] text-text-muted">From</label>
              <input
                type="date"
                value={dateFrom ?? ''}
                onChange={(e) => setDateFrom(e.target.value || null)}
                className="w-full rounded border border-border bg-bg px-2 py-1 text-xs text-text"
              />
            </div>
            <div>
              <label className="mb-1 block text-[11px] text-text-muted">To</label>
              <input
                type="date"
                value={dateTo ?? ''}
                onChange={(e) => setDateTo(e.target.value || null)}
                className="w-full rounded border border-border bg-bg px-2 py-1 text-xs text-text"
              />
            </div>
          </div>
        </FilterPill>

        {/* Type */}
        <FilterPill
          label="Type"
          value={typeValue}
          isActive={typeActive}
          onClear={() => mediaTypes.forEach((t) => toggleMediaType(t))}
        >
          <div className="flex flex-wrap gap-1">
            {MEDIA_TYPES.map(({ value, label }) => {
              const active = mediaTypes.includes(value)
              return (
                <button
                  key={value}
                  onClick={() => toggleMediaType(value)}
                  className={clsx(
                    'rounded px-2 py-1 text-xs transition-colors',
                    active
                      ? 'bg-primary text-white'
                      : 'bg-surface-2 text-text-muted hover:bg-surface-offset hover:text-text'
                  )}
                >
                  {label}
                </button>
              )
            })}
          </div>
        </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={clsx(
                      '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={clsx(
                    '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. The Needs review
       *  option lives here too: it sets a different store field
       *  (`needsReview`) but is mutually exclusive with the other flag
       *  values from the user's perspective. */}
        {!hideFlagPill && (
          <FilterPill
            label="Flag"
            value={flagValue}
            isActive={flagActive}
            onClear={() => {
              setFlag('any')
              setNeedsReview(false)
            }}
          >
            <div className="flex flex-col gap-1">
              <button
                onClick={() => {
                  setFlag('any')
                  setNeedsReview(false)
                }}
                className={clsx(
                  'rounded px-2 py-1 text-left text-xs transition-colors',
                  flag === 'any' && !needsReview
                    ? 'bg-primary text-white'
                    : 'bg-surface-2 text-text-muted hover:bg-surface-offset hover:text-text'
                )}
              >
                Any
              </button>
              <button
                onClick={() => {
                  setFlag('discarded')
                  setNeedsReview(false)
                }}
                className={clsx(
                  'rounded px-2 py-1 text-left text-xs transition-colors',
                  flag === 'discarded'
                    ? 'bg-primary text-white'
                    : 'bg-surface-2 text-text-muted hover:bg-surface-offset hover:text-text'
                )}
              >
                Discarded
              </button>
              <button
                onClick={() => {
                  setFlag('date_warning')
                  setNeedsReview(false)
                }}
                className={clsx(
                  'flex items-center gap-1.5 rounded px-2 py-1 text-left text-xs transition-colors',
                  flag === 'date_warning'
                    ? 'bg-primary text-white'
                    : 'bg-surface-2 text-text-muted hover:bg-surface-offset hover:text-text'
                )}
                title="Photos whose folder/filename suggests a different date than the stored taken_at"
              >
                <AlertTriangle className="h-3 w-3" />
                Date issues
              </button>
              <button
                onClick={() => {
                  setFlag('any')
                  setNeedsReview(true)
                }}
                className={clsx(
                  'flex items-center gap-1.5 rounded px-2 py-1 text-left text-xs transition-colors',
                  needsReview
                    ? 'bg-primary text-white'
                    : 'bg-surface-2 text-text-muted hover:bg-surface-offset hover:text-text'
                )}
                title="Show only photos classified as non-photographs (screenshots, documents, memes)"
              >
                <AlertTriangle className="h-3 w-3" />
                Needs review
              </button>
            </div>
          </FilterPill>
        )}

        {/* Tags */}
        {allTags.length > 0 && (
          <FilterPill
            label="Tags"
            value={tagValue}
            isActive={tagActive}
            onClear={() => setTagIds([])}
          >
            <TagFilterPopover
              allTags={allTags}
              selectedIds={tagIds}
              onToggle={toggleTagId}
              onClear={() => 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}
              onChange={(e) => setSortBy(e.target.value as SortField)}
              className="w-full rounded border border-border bg-bg px-2 py-1 text-xs text-text focus:border-primary focus:outline-none"
            >
              {SORT_OPTIONS.map((opt) => (
                <option key={opt.value} value={opt.value}>
                  {opt.label}
                </option>
              ))}
            </select>
            <button
              onClick={toggleSortOrder}
              className="flex w-full items-center justify-center gap-1 rounded bg-surface-2 px-2 py-1 text-xs text-text-muted hover:bg-surface-offset hover:text-text"
            >
              {sortOrder === 'desc' ? (
                <>
                  <ArrowDown className="h-3.5 w-3.5" />
                  Descending
                </>
              ) : (
                <>
                  <ArrowUp className="h-3.5 w-3.5" />
                  Ascending
                </>
              )}
            </button>
          </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>

      {/* Search — pinned to the right edge of the bar. Same id as before
       *  so the global "/" focus shortcut still finds it. */}
      <div className="relative w-56 flex-shrink-0">
        <Search className="pointer-events-none absolute left-2.5 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-text-muted" />
        <input
          id="topbar-search"
          type="text"
          value={searchQuery}
          onChange={(e) => setSearchQuery(e.target.value)}
          onKeyDown={(e) => {
            if (e.key === 'Escape') {
              setSearchQuery('')
              setStoreQ('')
              e.currentTarget.blur()
            }
          }}
          placeholder="Search photos…"
          className="h-7 w-full rounded-full border border-border bg-surface-2 pl-8 pr-7 text-xs text-text placeholder-text-muted focus:border-primary focus:outline-none"
        />
        {searchQuery && (
          <button
            onClick={() => {
              setSearchQuery('')
              setStoreQ('')
            }}
            className="absolute right-1.5 top-1/2 -translate-y-1/2 rounded-full p-0.5 text-text-muted hover:bg-surface-offset hover:text-text"
            title="Clear search (Esc)"
            aria-label="Clear search"
          >
            <X className="h-3 w-3" />
          </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>
  )
}

interface TagFilterPopoverProps {
  allTags: Tag[]
  selectedIds: string[]
  onToggle: (id: string) => void
  onClear: () => void
}

function TagFilterPopover({
  allTags,
  selectedIds,
  onToggle,
  onClear,
}: TagFilterPopoverProps) {
  const [query, setQuery] = useState('')
  const inputRef = useRef<HTMLInputElement>(null)

  useEffect(() => {
    inputRef.current?.focus()
  }, [])

  const selectedSet = useMemo(() => new Set(selectedIds), [selectedIds])

  // Selected tags pinned at top, remaining sorted by photo_count desc
  // then name. Filtered by query (case-insensitive substring).
  const orderedTags = useMemo(() => {
    const q = query.trim().toLowerCase()
    const match = (t: Tag) => !q || t.name.toLowerCase().includes(q)
    const selected = allTags.filter((t) => selectedSet.has(t.id) && match(t))
    const unselected = allTags
      .filter((t) => !selectedSet.has(t.id) && match(t))
      .sort((a, b) => {
        if (b.photo_count !== a.photo_count) return b.photo_count - a.photo_count
        return a.name.localeCompare(b.name)
      })
    return { selected, unselected }
  }, [allTags, selectedSet, query])

  const totalVisible = orderedTags.selected.length + orderedTags.unselected.length

  return (
    <div className="w-64">
      <div className="relative mb-2">
        <Search className="pointer-events-none absolute left-2 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-text-muted" />
        <input
          ref={inputRef}
          type="text"
          value={query}
          onChange={(e) => setQuery(e.target.value)}
          onKeyDown={(e) => {
            if (e.key === 'Escape' && query) {
              e.stopPropagation()
              setQuery('')
            }
          }}
          placeholder="Search tags…"
          className="h-7 w-full rounded border border-border bg-bg pl-7 pr-6 text-xs text-text placeholder-text-muted focus:border-primary focus:outline-none"
        />
        {query && (
          <button
            onClick={() => setQuery('')}
            className="absolute right-1 top-1/2 -translate-y-1/2 rounded p-0.5 text-text-muted hover:bg-surface-2 hover:text-text"
            aria-label="Clear search"
          >
            <X className="h-3 w-3" />
          </button>
        )}
      </div>

      <div className="mb-1 flex items-center justify-between px-0.5 text-[11px] text-text-muted">
        <span>
          {selectedIds.length > 0
            ? `${selectedIds.length} selected`
            : `${totalVisible} tag${totalVisible === 1 ? '' : 's'}`}
        </span>
        {selectedIds.length > 0 && (
          <button
            onClick={onClear}
            className="underline-offset-2 hover:text-text hover:underline"
          >
            Clear
          </button>
        )}
      </div>

      <div className="max-h-64 overflow-y-auto rounded border border-border bg-bg">
        {totalVisible === 0 ? (
          <div className="px-2 py-3 text-center text-xs text-text-muted">
            No tags match
          </div>
        ) : (
          <>
            {orderedTags.selected.map((tag) => (
              <TagRow key={tag.id} tag={tag} selected onToggle={onToggle} />
            ))}
            {orderedTags.selected.length > 0 && orderedTags.unselected.length > 0 && (
              <div className="my-0.5 border-t border-border" />
            )}
            {orderedTags.unselected.map((tag) => (
              <TagRow key={tag.id} tag={tag} selected={false} onToggle={onToggle} />
            ))}
          </>
        )}
      </div>
    </div>
  )
}

function TagRow({
  tag,
  selected,
  onToggle,
}: {
  tag: Tag
  selected: boolean
  onToggle: (id: string) => void
}) {
  return (
    <button
      onClick={() => onToggle(tag.id)}
      className={clsx(
        'flex w-full items-center gap-2 px-2 py-1.5 text-left text-xs transition-colors',
        selected
          ? 'bg-primary/15 text-text hover:bg-primary/25'
          : 'text-text-muted hover:bg-surface-2 hover:text-text'
      )}
    >
      <span
        className={clsx(
          'flex h-3.5 w-3.5 flex-shrink-0 items-center justify-center rounded border',
          selected ? 'border-primary bg-primary text-white' : 'border-border'
        )}
      >
        {selected && <Check className="h-2.5 w-2.5" strokeWidth={3} />}
      </span>
      <span className="min-w-0 flex-1 truncate">{tag.name}</span>
      <span className="flex-shrink-0 tabular-nums text-[10px] text-text-muted">
        {tag.photo_count}
      </span>
    </button>
  )
}
