import clsx from 'clsx';
/**
 * Tag picker for entity detail pages.
 * Shows assigned tags and allows assigning/unassigning tags.
 */

import React, { useState, useEffect, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
import { Badge } from '@/components/ui/Badge';
import { Button } from '@/components/ui/Button';
import { Input } from '@/components/ui/Input';
import { EmptyState } from '@/components/ui/EmptyState';
import { useToast } from '@/components/ui/Toast';
import { X } from 'lucide-react';
import {
  fetchTags,
  assignTag,
  unassignTag,
  createTag,
  type Tag,
  type EntityType,
} from '@/api/tags';

export interface TagPickerProps {
  entityType: EntityType;
  entityId: string;
  assignedTags?: Tag[];
}

export function TagPicker({ entityType, entityId, assignedTags: initialAssigned = [] }: TagPickerProps) {
  const { t } = useTranslation();
  const toast = useToast();
  const [allTags, setAllTags] = useState<Tag[]>([]);
  const [assignedTags, setAssignedTags] = useState<Tag[]>(initialAssigned);
  const [loading, setLoading] = useState(true);
  const [showCreateForm, setShowCreateForm] = useState(false);
  const [searchQuery, setSearchQuery] = useState('');
  const [submitting, setSubmitting] = useState(false);

  // ── Tag create form (RHF + Zod) ──
  const tagSchema = z.object({
    name: z.string().min(1, 'required'),
    color: z.string().optional().default('#3B82F6'),
  });
  type TagFormData = z.infer<typeof tagSchema>;

  const { register: registerTag, handleSubmit: handleSubmitTag, reset: resetTag, watch: watchTag, setValue: setTagValue, formState: { errors: tagErrors } } = useForm<TagFormData>({
    resolver: zodResolver(tagSchema),
    defaultValues: { name: '', color: '#3B82F6' },
  });

  const newTagColor = watchTag('color');

  useEffect(() => {
    let cancelled = false;
    setLoading(true);
    fetchTags()
      .then((tags) => {
        if (cancelled) return;
        setAllTags(tags);
      })
      .catch((err) => {
        if (cancelled) return;
        const msg = err instanceof Error ? err.message : String(err);
        toast.error(msg);
      })
      .finally(() => {
        if (!cancelled) setLoading(false);
      });
    return () => { cancelled = true; };
  }, [toast]);

  const assignedTagIds = new Set(assignedTags.map((tag) => tag.id));

  const filteredTags = allTags.filter((tag) => {
    const matchesSearch = tag.name.toLowerCase().includes(searchQuery.toLowerCase());
    const isAssigned = assignedTagIds.has(tag.id);
    return matchesSearch && !isAssigned;
  });

  const handleAssign = useCallback(async (tagId: string) => {
    setSubmitting(true);
    try {
      await assignTag({ tag_id: tagId, entity_type: entityType, entity_id: entityId });
      const tag = allTags.find((t) => t.id === tagId) || assignedTags.find((t) => t.id === tagId);
      if (tag) {
        setAssignedTags((prev) => [...prev, tag]);
      }
      toast.success(t('tags.assignSuccess'));
    } catch (err) {
      const msg = err instanceof Error ? err.message : String(err);
      toast.error(msg);
    }
    setSubmitting(false);
  }, [entityType, entityId, allTags, assignedTags, toast, t]);

  const handleUnassign = useCallback(async (tagId: string) => {
    setSubmitting(true);
    try {
      await unassignTag({ tag_id: tagId, entity_type: entityType, entity_id: entityId });
      setAssignedTags((prev) => prev.filter((tag) => tag.id !== tagId));
      toast.success(t('tags.unassignSuccess'));
    } catch (err) {
      const msg = err instanceof Error ? err.message : String(err);
      toast.error(msg);
    }
    setSubmitting(false);
  }, [entityType, entityId, toast, t]);

  const handleCreateTag = useCallback(async (data: TagFormData) => {
    setSubmitting(true);
    try {
      const tag = await createTag({ name: data.name.trim(), color: data.color });
      setAllTags((prev) => [...prev, tag]);
      await handleAssign(tag.id);
      resetTag({ name: '', color: '#3B82F6' });
      setShowCreateForm(false);
      toast.success(t('tags.createSuccess'));
    } catch (err) {
      const msg = err instanceof Error ? err.message : String(err);
      toast.error(msg);
    }
    setSubmitting(false);
  }, [handleAssign, toast, t, resetTag]);

  const colorOptions = ['#3B82F6', '#EF4444', '#10B981', '#F59E0B', '#8B5CF6', '#F97316', '#EC4899', '#6B7280'];

  return (
    <div className="space-y-4" data-testid="tag-picker">
      {/* Assigned tags */}
      <div className="space-y-2">
        <h3 className="text-sm font-semibold text-secondary-900">{t('tags.assignedTags')}</h3>
        {loading ? (
          <p className="text-sm text-secondary-500">{t('tags.loading')}...</p>
        ) : assignedTags.length === 0 ? (
          <EmptyState title={t('tags.noTagsAssigned')} />
        ) : (
          <div className="flex flex-wrap gap-2" role="list" aria-label={t('tags.assignedTags')}>
            {assignedTags.map((tag) => (
              <div key={tag.id} className="flex items-center">
                <Badge
                  variant="primary"
                  className="cursor-default"
                >
                  <span
                    className="w-2 h-2 rounded-full inline-block mr-1"
                    style={{ backgroundColor: tag.color }}
                    aria-hidden="true"
                  />
                  {tag.name}
                </Badge>
                <button
                  onClick={() => handleUnassign(tag.id)}
                  className="ml-1 text-secondary-400 hover:text-danger-600 min-h-touch min-w-touch"
                  aria-label={t('tags.removeTag')}
                  disabled={submitting}
                >
                  <X className="w-3 h-3" aria-hidden="true" strokeWidth={2} />
                </button>
              </div>
            ))}
          </div>
        )}
      </div>

      {/* Search and assign */}
      <div className="space-y-3">
        <Input
          label={t('tags.search')}
          value={searchQuery}
          onChange={(e) => setSearchQuery(e.target.value)}
          placeholder={t('tags.search')}
        />
        {filteredTags.length > 0 && (
          <div className="flex flex-wrap gap-2" role="list" aria-label={t('tags.availableTags')} data-testid="available-tags-list">
            {filteredTags.map((tag) => (
              <button
                key={tag.id}
                onClick={() => handleAssign(tag.id)}
                disabled={submitting}
                className="inline-flex items-center gap-1.5 px-2.5 py-0.5 rounded-full text-xs font-medium bg-secondary-100 text-secondary-700 hover:bg-primary-100 hover:text-primary-700 motion-safe:transition-colors min-h-touch disabled:opacity-50"
                aria-label={t('tags.addTag')}
              >
                <span
                  className="w-2 h-2 rounded-full inline-block"
                  style={{ backgroundColor: tag.color }}
                  aria-hidden="true"
                />
                {tag.name}
              </button>
            ))}
          </div>
        )}
        {searchQuery && filteredTags.length === 0 && !loading && (
          <p className="text-sm text-secondary-500">{t('tags.noTags')}</p>
        )}

        {/* Create new tag */}
        {!showCreateForm ? (
          <Button
            variant="ghost"
            size="sm"
            onClick={() => setShowCreateForm(true)}
          >
            {t('tags.create')}
          </Button>
        ) : (
          <div className="space-y-3 p-4 border border-secondary-200 rounded-lg" data-testid="create-tag-form">
            <form onSubmit={handleSubmitTag(handleCreateTag)}>
            <Input
              label={t('tags.tagName')}
              {...registerTag('name')}
              error={tagErrors.name?.message === 'required' ? t('validation.required') : undefined}
              placeholder={t('tags.tagName')}
            />
            <div className="space-y-1">
              <label className="block text-sm font-medium text-secondary-700">{t('tags.tagColor')}</label>
              <div className="flex items-center gap-2">
                {colorOptions.map((color) => (
                  <button
                    key={color}
                    type="button"
                    onClick={() => setTagValue('color', color)}
                    className={clsx(
                      'w-6 h-6 rounded-full transition-transform',
                      newTagColor === color ? 'ring-2 ring-offset-2 ring-secondary-400 scale-110' : ''
                    )}
                    style={{ backgroundColor: color }}
                    aria-label={`${t('tags.tagColor')}: ${color}`}
                    aria-pressed={newTagColor === color}
                  />
                ))}
              </div>
            </div>
            <div className="flex gap-2">
              <Button size="sm" type="submit" isLoading={submitting}>{t('tags.save')}</Button>
              <Button variant="secondary" size="sm" type="button" onClick={() => setShowCreateForm(false)}>{t('tags.cancel')}</Button>
            </div>
            </form>
          </div>
        )}
      </div>
    </div>
  );
}
