'use client'

import { useState, useRef, useEffect, useCallback } from 'react'
import { trpc } from '@/lib/trpc/client'
import { Badge } from '@/components/ui/badge'
import { Button } from '@/components/ui/button'
import {
  Command,
  CommandEmpty,
  CommandGroup,
  CommandInput,
  CommandItem,
  CommandList,
} from '@/components/ui/command'
import {
  Popover,
  PopoverContent,
  PopoverTrigger,
} from '@/components/ui/popover'
import { X, ChevronsUpDown, Check, Loader2 } from 'lucide-react'
import { cn } from '@/lib/utils'

interface Tag {
  id: string
  name: string
  description: string | null
  category: string | null
  color: string | null
  isActive: boolean
}

interface TagInputProps {
  value: string[]
  onChange: (tags: string[]) => void
  placeholder?: string
  maxTags?: number
  disabled?: boolean
  className?: string
  showCategories?: boolean
}

export function TagInput({
  value,
  onChange,
  placeholder = 'Select tags...',
  maxTags,
  disabled = false,
  className,
  showCategories = true,
}: TagInputProps) {
  const [open, setOpen] = useState(false)
  const [search, setSearch] = useState('')
  const inputRef = useRef<HTMLInputElement>(null)

  const { data: tagsData, isLoading } = trpc.tag.list.useQuery({
    isActive: true,
  })

  const tags = tagsData?.tags || []

  // Group tags by category
  const tagsByCategory = tags.reduce(
    (acc, tag) => {
      const category = tag.category || 'Other'
      if (!acc[category]) {
        acc[category] = []
      }
      acc[category].push(tag)
      return acc
    },
    {} as Record<string, Tag[]>
  )

  // Filter tags based on search
  const filteredTags = tags.filter((tag) =>
    tag.name.toLowerCase().includes(search.toLowerCase())
  )

  // Group filtered tags by category
  const filteredByCategory = filteredTags.reduce(
    (acc, tag) => {
      const category = tag.category || 'Other'
      if (!acc[category]) {
        acc[category] = []
      }
      acc[category].push(tag)
      return acc
    },
    {} as Record<string, Tag[]>
  )

  const handleSelect = useCallback(
    (tagName: string) => {
      if (value.includes(tagName)) {
        onChange(value.filter((t) => t !== tagName))
      } else {
        if (maxTags && value.length >= maxTags) return
        onChange([...value, tagName])
      }
      setSearch('')
    },
    [value, onChange, maxTags]
  )

  const handleRemove = useCallback(
    (tagName: string) => {
      onChange(value.filter((t) => t !== tagName))
    },
    [value, onChange]
  )

  // Get tag details for selected tags
  const selectedTagDetails = value
    .map((name) => tags.find((t) => t.name === name))
    .filter((t) => t != null)

  return (
    <div className={cn('space-y-2', className)}>
      <Popover open={open} onOpenChange={setOpen}>
        <PopoverTrigger asChild>
          <Button
            variant="outline"
            role="combobox"
            aria-expanded={open}
            disabled={disabled}
            className={cn(
              'w-full justify-between font-normal',
              !value.length && 'text-muted-foreground'
            )}
          >
            {value.length > 0 ? `${value.length} tag(s) selected` : placeholder}
            {isLoading ? (
              <Loader2 className="ml-2 h-4 w-4 shrink-0 animate-spin opacity-50" />
            ) : (
              <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
            )}
          </Button>
        </PopoverTrigger>
        <PopoverContent className="w-full p-0" align="start">
          <Command shouldFilter={false}>
            <CommandInput
              ref={inputRef}
              placeholder="Search tags..."
              value={search}
              onValueChange={setSearch}
            />
            <CommandList>
              {isLoading ? (
                <div className="p-4 text-center text-sm text-muted-foreground">
                  Loading tags...
                </div>
              ) : filteredTags.length === 0 ? (
                <CommandEmpty>No tags found.</CommandEmpty>
              ) : showCategories ? (
                // Show grouped by category
                Object.entries(filteredByCategory)
                  .sort(([a], [b]) => a.localeCompare(b))
                  .map(([category, categoryTags]) => (
                    <CommandGroup key={category} heading={category}>
                      {categoryTags.map((tag) => {
                        const isSelected = value.includes(tag.name)
                        const isDisabled =
                          !isSelected && !!maxTags && value.length >= maxTags

                        return (
                          <CommandItem
                            key={tag.id}
                            value={tag.name}
                            onSelect={() => handleSelect(tag.name)}
                            disabled={isDisabled}
                            className={cn(
                              isDisabled && 'opacity-50 cursor-not-allowed'
                            )}
                          >
                            <div className="flex items-center gap-2 flex-1">
                              <div
                                className="h-3 w-3 rounded-full shrink-0"
                                style={{
                                  backgroundColor: tag.color || '#6b7280',
                                }}
                              />
                              <span>{tag.name}</span>
                              {tag.description && (
                                <span className="text-xs text-muted-foreground truncate">
                                  - {tag.description}
                                </span>
                              )}
                            </div>
                            <Check
                              className={cn(
                                'ml-2 h-4 w-4',
                                isSelected ? 'opacity-100' : 'opacity-0'
                              )}
                            />
                          </CommandItem>
                        )
                      })}
                    </CommandGroup>
                  ))
              ) : (
                // Flat list
                <CommandGroup>
                  {filteredTags.map((tag) => {
                    const isSelected = value.includes(tag.name)
                    const isDisabled =
                      !isSelected && !!maxTags && value.length >= maxTags

                    return (
                      <CommandItem
                        key={tag.id}
                        value={tag.name}
                        onSelect={() => handleSelect(tag.name)}
                        disabled={isDisabled}
                        className={cn(
                          isDisabled && 'opacity-50 cursor-not-allowed'
                        )}
                      >
                        <div className="flex items-center gap-2 flex-1">
                          <div
                            className="h-3 w-3 rounded-full shrink-0"
                            style={{
                              backgroundColor: tag.color || '#6b7280',
                            }}
                          />
                          <span>{tag.name}</span>
                        </div>
                        <Check
                          className={cn(
                            'ml-2 h-4 w-4',
                            isSelected ? 'opacity-100' : 'opacity-0'
                          )}
                        />
                      </CommandItem>
                    )
                  })}
                </CommandGroup>
              )}
            </CommandList>
          </Command>
        </PopoverContent>
      </Popover>

      {/* Selected tags display */}
      {value.length > 0 && (
        <div className="flex flex-wrap gap-1.5">
          {selectedTagDetails.length > 0
            ? selectedTagDetails.map((tag) => (
                <Badge
                  key={tag.id}
                  variant="secondary"
                  className="gap-1 pr-1"
                  style={{
                    backgroundColor: tag.color
                      ? `${tag.color}20`
                      : undefined,
                    borderColor: tag.color || undefined,
                  }}
                >
                  <div
                    className="h-2 w-2 rounded-full"
                    style={{ backgroundColor: tag.color || '#6b7280' }}
                  />
                  {tag.name}
                  {!disabled && (
                    <button
                      type="button"
                      onClick={() => handleRemove(tag.name)}
                      className="ml-1 rounded-full p-0.5 hover:bg-muted"
                      aria-label={`Remove ${tag.name}`}
                    >
                      <X className="h-3 w-3" />
                    </button>
                  )}
                </Badge>
              ))
            : // Fallback for tags not found in system (legacy data)
              value.map((tagName) => (
                <Badge key={tagName} variant="secondary" className="gap-1 pr-1">
                  {tagName}
                  {!disabled && (
                    <button
                      type="button"
                      onClick={() => handleRemove(tagName)}
                      className="ml-1 rounded-full p-0.5 hover:bg-muted"
                      aria-label={`Remove ${tagName}`}
                    >
                      <X className="h-3 w-3" />
                    </button>
                  )}
                </Badge>
              ))}
        </div>
      )}

      {maxTags && (
        <p className="text-xs text-muted-foreground">
          {value.length} / {maxTags} tags selected
        </p>
      )}
    </div>
  )
}

// Simple variant for inline display (read-only)
interface TagDisplayProps {
  tags: string[]
  className?: string
  maxDisplay?: number
}

export function TagDisplay({
  tags,
  className,
  maxDisplay = 5,
}: TagDisplayProps) {
  const { data: tagsData } = trpc.tag.list.useQuery({ isActive: true })
  const allTags = tagsData?.tags || []

  const displayTags = tags.slice(0, maxDisplay)
  const remaining = tags.length - maxDisplay

  const getTagColor = (name: string) => {
    const tag = allTags.find((t) => t.name === name)
    return tag?.color || '#6b7280'
  }

  if (tags.length === 0) {
    return (
      <span className={cn('text-muted-foreground text-sm', className)}>
        No tags
      </span>
    )
  }

  return (
    <div className={cn('flex flex-wrap gap-1', className)}>
      {displayTags.map((tag) => (
        <Badge
          key={tag}
          variant="secondary"
          className="text-xs"
          style={{
            backgroundColor: `${getTagColor(tag)}20`,
            borderColor: getTagColor(tag),
          }}
        >
          <div
            className="h-2 w-2 rounded-full mr-1"
            style={{ backgroundColor: getTagColor(tag) }}
          />
          {tag}
        </Badge>
      ))}
      {remaining > 0 && (
        <Badge variant="outline" className="text-xs">
          +{remaining} more
        </Badge>
      )}
    </div>
  )
}
