/**
 * ProvidersPanel Component
 *
 * Provider management panel: list providers, test connections, manage custom providers/models
 */

import { useState, useEffect, useCallback } from 'react';
import {
  X,
  RefreshCw,
  Server,
  Plus,
  ChevronDown,
  ChevronRight,
  Trash2,
  Check,
  AlertCircle,
  Loader2,
  Cpu,
  Key,
  Globe,
  Zap,
  Settings,
} from 'lucide-react';
import { motion, AnimatePresence } from 'framer-motion';
import { toast } from 'sonner';
import { cn } from '../utils/cn';
import { modalOverlay, modalContent, smoothTransition } from '../utils/animations';
import { Button } from '../primitives/Button';
import { Input } from '../primitives/Input';
import { Skeleton } from './Skeleton';
import {
  listProviders,
  getProvider,
  testProviderConnection,
  registerProvider,
  deleteProvider,
  addProviderModel,
  deleteProviderModel,
  type ProviderListItem,
  type ProviderDetail,
  type ModelInfo,
  type CustomProviderDefinition,
} from '../api/client.js';
import { ProviderEditor } from './ProviderEditor.js';

interface ProvidersPanelProps {
  onClose: () => void;
  /** Enable responsive layout */
  responsive?: boolean;
}

export function ProvidersPanel({ onClose, responsive = false }: ProvidersPanelProps) {
  // Data state
  const [providers, setProviders] = useState<ProviderListItem[]>([]);
  const [expandedProviders, setExpandedProviders] = useState<Set<string>>(new Set());
  const [providerDetails, setProviderDetails] = useState<Record<string, ProviderDetail>>({});

  // UI state
  const [loading, setLoading] = useState(true);
  const [refreshing, setRefreshing] = useState(false);
  const [testingProvider, setTestingProvider] = useState<string | null>(null);
  const [testResults, setTestResults] = useState<Record<string, { success: boolean; error?: string }>>({});

  // Editor state
  const [showAddProvider, setShowAddProvider] = useState(false);
  const [showAddModel, setShowAddModel] = useState<string | null>(null);
  const [editingProviderId, setEditingProviderId] = useState<string | null>(null);
  const [newProvider, setNewProvider] = useState<Partial<CustomProviderDefinition>>({});
  const [newModel, setNewModel] = useState<Partial<ModelInfo>>({});

  // Load provider list
  const loadProviders = useCallback(async (showToast = false) => {
    try {
      const result = await listProviders();
      if (result.success) {
        setProviders(result.data);
        if (showToast) {
          toast.success('Providers refreshed');
        }
      } else {
        toast.error(result.error || 'Failed to load providers');
      }
    } catch (err) {
      toast.error(err instanceof Error ? err.message : 'Failed to load providers');
    }
  }, []);

  // Initial load
  useEffect(() => {
    setLoading(true);
    loadProviders().finally(() => setLoading(false));
  }, [loadProviders]);

  // Refresh
  const handleRefresh = async () => {
    setRefreshing(true);
    await loadProviders(true);
    setRefreshing(false);
  };

  // Load provider detail
  const loadProviderDetail = async (id: string) => {
    if (providerDetails[id]) return providerDetails[id];

    try {
      const result = await getProvider(id);
      if (result.success && result.data) {
        setProviderDetails((prev) => ({ ...prev, [id]: result.data! }));
        return result.data;
      }
    } catch (err) {
      toast.error(`Failed to load provider details: ${err instanceof Error ? err.message : 'Unknown error'}`);
    }
    return null;
  };

  // Toggle expanded
  const toggleExpanded = async (id: string) => {
    const newExpanded = new Set(expandedProviders);
    if (newExpanded.has(id)) {
      newExpanded.delete(id);
    } else {
      newExpanded.add(id);
      await loadProviderDetail(id);
    }
    setExpandedProviders(newExpanded);
  };

  // Test connection
  const handleTestConnection = async (id: string) => {
    setTestingProvider(id);
    try {
      const result = await testProviderConnection(id);
      if (result.success) {
        setTestResults((prev) => ({ ...prev, [id]: result.data }));
        if (result.data.success) {
          toast.success(`${id} connection successful`);
        } else {
          toast.error(result.data.error || `${id} connection failed`);
        }
      } else {
        setTestResults((prev) => ({ ...prev, [id]: { success: false, error: result.error } }));
        toast.error(result.error || 'Test failed');
      }
    } catch (err) {
      const error = err instanceof Error ? err.message : 'Test failed';
      setTestResults((prev) => ({ ...prev, [id]: { success: false, error } }));
      toast.error(error);
    } finally {
      setTestingProvider(null);
    }
  };

  // Add custom provider
  const handleAddProvider = async () => {
    if (!newProvider.id || !newProvider.name || !newProvider.baseUrl) {
      toast.error('ID, Name, and Base URL are required');
      return;
    }

    try {
      const result = await registerProvider(newProvider as CustomProviderDefinition);
      if (result.success) {
        toast.success(`Provider ${newProvider.id} added`);
        setShowAddProvider(false);
        setNewProvider({});
        loadProviders();
      } else {
        toast.error(result.error || 'Failed to add provider');
      }
    } catch (err) {
      toast.error(err instanceof Error ? err.message : 'Failed to add provider');
    }
  };

  // Delete custom provider
  const handleDeleteProvider = async (id: string) => {
    if (!confirm(`Are you sure you want to delete provider "${id}"?`)) return;

    try {
      const result = await deleteProvider(id);
      if (result.success) {
        toast.success(`Provider ${id} deleted`);
        loadProviders();
        setProviderDetails((prev) => {
          const newDetails = { ...prev };
          delete newDetails[id];
          return newDetails;
        });
      } else {
        toast.error(result.error || 'Delete failed');
      }
    } catch (err) {
      toast.error(err instanceof Error ? err.message : 'Delete failed');
    }
  };

  // Add custom model
  const handleAddModel = async (providerId: string) => {
    if (!newModel.id || !newModel.name) {
      toast.error('Model ID and Name are required');
      return;
    }

    try {
      const result = await addProviderModel(providerId, newModel as ModelInfo);
      if (result.success) {
        toast.success(`Model ${newModel.id} added to ${providerId}`);
        setShowAddModel(null);
        setNewModel({});
        // Reload provider detail
        setProviderDetails((prev) => {
          const newDetails = { ...prev };
          delete newDetails[providerId];
          return newDetails;
        });
        await loadProviderDetail(providerId);
      } else {
        toast.error(result.error || 'Failed to add model');
      }
    } catch (err) {
      toast.error(err instanceof Error ? err.message : 'Failed to add model');
    }
  };

  // Delete custom model
  const handleDeleteModel = async (providerId: string, modelId: string) => {
    if (!confirm(`Are you sure you want to delete model "${modelId}"?`)) return;

    try {
      const result = await deleteProviderModel(providerId, modelId);
      if (result.success) {
        toast.success(`Model ${modelId} deleted`);
        // Reload provider detail
        setProviderDetails((prev) => {
          const newDetails = { ...prev };
          delete newDetails[providerId];
          return newDetails;
        });
        await loadProviderDetail(providerId);
      } else {
        toast.error(result.error || 'Delete failed');
      }
    } catch (err) {
      toast.error(err instanceof Error ? err.message : 'Delete failed');
    }
  };

  // Statistics
  const builtinProviders = providers.filter((p) => p.builtin);
  const customProviders = providers.filter((p) => !p.builtin);

  // Loading skeleton
  const LoadingSkeleton = () => (
    <div className="space-y-3 p-4">
      {[1, 2, 3].map((i) => (
        <div key={i} className="flex items-center gap-3 p-3 bg-surface-base/50 rounded-lg">
          <Skeleton className="h-4 w-4" />
          <div className="flex-1 space-y-2">
            <Skeleton className="h-4 w-32" />
            <Skeleton className="h-3 w-48" />
          </div>
          <Skeleton className="h-6 w-16 rounded-full" />
        </div>
      ))}
    </div>
  );

  // Provider item component
  const ProviderItem = ({ provider }: { provider: ProviderListItem }) => {
    const isExpanded = expandedProviders.has(provider.id);
    const isTesting = testingProvider === provider.id;
    const testResult = testResults[provider.id];
    const detail = providerDetails[provider.id];

    return (
      <motion.div
        layout
        initial={{ opacity: 0, y: 10 }}
        animate={{ opacity: 1, y: 0 }}
        className="bg-surface-base/50 rounded-lg overflow-hidden"
      >
        {/* Provider Header */}
        <div
          className={cn(
            'flex items-center gap-3 p-3',
            'hover:bg-surface-base/80 transition-colors cursor-pointer'
          )}
          onClick={() => toggleExpanded(provider.id)}
        >
          {/* Expand Icon */}
          <button className="text-fg-subtle hover:text-fg-secondary">
            {isExpanded ? <ChevronDown size={16} /> : <ChevronRight size={16} />}
          </button>

          {/* Icon */}
          {provider.builtin ? (
            <Server size={16} className="text-blue-400" />
          ) : (
            <Globe size={16} className="text-green-400" />
          )}

          {/* Info */}
          <div className="flex-1 min-w-0">
            <div className="flex items-center gap-2">
              <span className="font-medium text-fg-secondary">{provider.name}</span>
              <span
                className={cn(
                  'text-xs px-2 py-0.5 rounded-full',
                  provider.builtin ? 'bg-blue-500/20 text-blue-400' : 'bg-green-500/20 text-green-400'
                )}
              >
                {provider.builtin ? 'Built-in' : 'Custom'}
              </span>
            </div>
            <div className="text-xs text-fg-subtle flex items-center gap-2">
              <span>{provider.modelCount} models</span>
              {provider.hasApiKey ? (
                <span className="text-green-400 flex items-center gap-1">
                  <Key size={10} />
                  Configured
                </span>
              ) : (
                <span className="text-yellow-400 flex items-center gap-1">
                  <Key size={10} />
                  No API Key
                </span>
              )}
            </div>
          </div>

          {/* Status & Actions */}
          <div className="flex items-center gap-2" onClick={(e) => e.stopPropagation()}>
            {/* Test Result */}
            {testResult && (
              testResult.success ? (
                <Check size={16} className="text-green-400" />
              ) : (
                <span title={testResult.error}>
                  <AlertCircle size={16} className="text-red-400" />
                </span>
              )
            )}

            {/* Test Button */}
            <Button
              variant="ghost"
              size="sm"
              onClick={() => handleTestConnection(provider.id)}
              disabled={isTesting}
              className="text-fg-muted hover:text-fg-secondary"
              title="Test Connection"
            >
              {isTesting ? (
                <Loader2 size={14} className="animate-spin" />
              ) : (
                <Zap size={14} />
              )}
            </Button>

            {/* Edit Button */}
            <Button
              variant="ghost"
              size="sm"
              onClick={() => setEditingProviderId(provider.id)}
              className="text-fg-muted hover:text-fg-secondary"
              title="Configure"
            >
              <Settings size={14} />
            </Button>

            {/* Delete (only for custom) */}
            {!provider.builtin && (
              <Button
                variant="ghost"
                size="sm"
                onClick={() => handleDeleteProvider(provider.id)}
                className="text-red-400 hover:text-red-300"
                title="Delete"
              >
                <Trash2 size={14} />
              </Button>
            )}
          </div>
        </div>

        {/* Expanded Content */}
        <AnimatePresence>
          {isExpanded && (
            <motion.div
              initial={{ height: 0, opacity: 0 }}
              animate={{ height: 'auto', opacity: 1 }}
              exit={{ height: 0, opacity: 0 }}
              transition={{ duration: 0.2 }}
              className="overflow-hidden"
            >
              <div className="px-4 pb-3 pt-1 border-t border-line/50 space-y-3">
                {detail ? (
                  <>
                    {/* Base URL */}
                    {detail.baseUrl && (
                      <div className="text-xs">
                        <span className="text-fg-muted">Base URL:</span>{' '}
                        <code className="text-fg-secondary bg-surface-subtle px-1 rounded">{detail.baseUrl}</code>
                      </div>
                    )}

                    {/* Models */}
                    <div className="space-y-2">
                      <div className="flex items-center justify-between">
                        <span className="text-xs text-fg-muted flex items-center gap-1">
                          <Cpu size={12} />
                          Models ({detail.models.length + detail.config.customModels.length})
                        </span>
                        {detail.allowCustomModels && (
                          <Button
                            variant="ghost"
                            size="sm"
                            onClick={() => setShowAddModel(provider.id)}
                            className="text-xs text-primary-400"
                          >
                            <Plus size={12} className="mr-1" />
                            Add Model
                          </Button>
                        )}
                      </div>

                      {/* Model List */}
                      <div className="space-y-1 max-h-48 overflow-y-auto">
                        {/* Built-in models */}
                        {detail.models.map((model) => (
                          <div
                            key={model.id}
                            className="flex items-center justify-between text-xs p-2 bg-surface-subtle/50 rounded"
                          >
                            <div>
                              <span className="text-fg-secondary">{model.name}</span>
                              <span className="text-fg-subtle ml-2">({model.id})</span>
                            </div>
                            <div className="flex items-center gap-2 text-fg-subtle">
                              {model.capabilities?.vision && (
                                <span title="Vision" className="text-[10px]">Vision</span>
                              )}
                              {model.capabilities?.functionCalling && (
                                <span title="Function Calling" className="text-[10px]">Tools</span>
                              )}
                            </div>
                          </div>
                        ))}

                        {/* Custom models */}
                        {detail.config.customModels.map((model) => (
                          <div
                            key={model.id}
                            className="flex items-center justify-between text-xs p-2 bg-surface-subtle/50 rounded border border-green-500/20"
                          >
                            <div>
                              <span className="text-fg-secondary">{model.name}</span>
                              <span className="text-fg-subtle ml-2">({model.id})</span>
                              <span className="text-green-400 ml-2 text-[10px]">custom</span>
                            </div>
                            <Button
                              variant="ghost"
                              size="sm"
                              onClick={() => handleDeleteModel(provider.id, model.id)}
                              className="text-red-400 hover:text-red-300 p-1"
                            >
                              <Trash2 size={12} />
                            </Button>
                          </div>
                        ))}
                      </div>
                    </div>
                  </>
                ) : (
                  <div className="flex items-center justify-center py-4">
                    <Loader2 className="animate-spin h-5 w-5 text-primary-500" />
                  </div>
                )}
              </div>
            </motion.div>
          )}
        </AnimatePresence>
      </motion.div>
    );
  };

  return (
    <AnimatePresence>
      <motion.div
        variants={modalOverlay}
        initial="initial"
        animate="animate"
        exit="exit"
        transition={{ duration: 0.2 }}
        className={cn(
          'fixed inset-0 bg-black/50 flex z-50',
          responsive ? 'items-end md:items-center justify-center' : 'items-center justify-center'
        )}
        onClick={onClose}
      >
        <motion.div
          variants={modalContent}
          initial="initial"
          animate="animate"
          exit="exit"
          transition={smoothTransition}
          onClick={(e) => e.stopPropagation()}
          className={cn(
            'bg-surface-subtle max-h-[90vh] overflow-hidden flex flex-col',
            responsive
              ? 'w-full md:w-full md:max-w-2xl md:mx-4 rounded-t-2xl md:rounded-lg'
              : 'rounded-lg w-full max-w-2xl mx-4'
          )}
        >
          {/* Header */}
          <div
            className={cn(
              'flex items-center justify-between border-b border-line',
              responsive ? 'px-4 md:px-6 py-4' : 'px-6 py-4'
            )}
          >
            {responsive && (
              <div className="absolute top-2 left-1/2 -translate-x-1/2 w-10 h-1 bg-surface-emphasis rounded-full md:hidden" />
            )}
            <div className={cn(responsive && 'mt-2 md:mt-0')}>
              <h2 className="text-lg font-semibold flex items-center gap-2">
                <Server size={20} className="text-primary-400" />
                Model Providers
              </h2>
              <p className="text-xs text-fg-subtle">
                {providers.length} providers ({builtinProviders.length} built-in, {customProviders.length} custom)
              </p>
            </div>
            <div className="flex items-center gap-2">
              <Button
                variant="ghost"
                size="icon"
                onClick={() => setShowAddProvider(true)}
                title="Add Provider"
                className={cn(responsive && 'min-w-[44px] min-h-[44px]')}
              >
                <Plus size={18} />
              </Button>
              <Button
                variant="ghost"
                size="icon"
                onClick={handleRefresh}
                disabled={refreshing}
                title="Refresh"
                className={cn(responsive && 'min-w-[44px] min-h-[44px]')}
              >
                <RefreshCw size={18} className={cn(refreshing && 'animate-spin')} />
              </Button>
              <Button
                variant="ghost"
                size="icon"
                onClick={onClose}
                className={cn(responsive && 'min-w-[44px] min-h-[44px]')}
              >
                <X size={20} />
              </Button>
            </div>
          </div>

          {/* Provider List */}
          <div className="flex-1 overflow-y-auto">
            {loading ? (
              <LoadingSkeleton />
            ) : providers.length === 0 ? (
              <div className="flex flex-col items-center justify-center py-12 text-fg-subtle">
                <Server size={48} className="mb-4 opacity-50" />
                <p className="text-center">No providers available</p>
              </div>
            ) : (
              <motion.div
                initial={{ opacity: 0 }}
                animate={{ opacity: 1 }}
                className={cn('space-y-4', responsive ? 'p-4' : 'p-4')}
              >
                {/* Built-in Providers */}
                {builtinProviders.length > 0 && (
                  <div>
                    <h3 className="text-xs font-medium text-fg-muted uppercase tracking-wide mb-2 flex items-center gap-2">
                      <Server size={12} />
                      Built-in Providers
                    </h3>
                    <div className="space-y-2">
                      {builtinProviders.map((provider) => (
                        <ProviderItem key={provider.id} provider={provider} />
                      ))}
                    </div>
                  </div>
                )}

                {/* Custom Providers */}
                <div>
                  <h3 className="text-xs font-medium text-fg-muted uppercase tracking-wide mb-2 flex items-center gap-2">
                    <Globe size={12} />
                    Custom Providers
                  </h3>
                  {customProviders.length > 0 ? (
                    <div className="space-y-2">
                      {customProviders.map((provider) => (
                        <ProviderItem key={provider.id} provider={provider} />
                      ))}
                    </div>
                  ) : (
                    <div className="text-center py-6 text-fg-subtle text-sm">
                      <p>No custom providers yet</p>
                      <Button
                        variant="ghost"
                        size="sm"
                        className="mt-2"
                        onClick={() => setShowAddProvider(true)}
                      >
                        <Plus size={14} className="mr-1" />
                        Add one
                      </Button>
                    </div>
                  )}
                </div>
              </motion.div>
            )}
          </div>

          {/* Footer */}
          <div
            className={cn(
              'border-t border-line text-xs text-fg-subtle text-center',
              responsive ? 'px-4 py-3 safe-area-pb' : 'px-6 py-3'
            )}
          >
            Config stored in{' '}
            <code className="font-mono bg-surface-base px-1 rounded">~/.ai-terminal-assistant/providers.json</code>
          </div>
        </motion.div>

        {/* Add Provider Dialog */}
        <AnimatePresence>
          {showAddProvider && (
            <motion.div
              initial={{ opacity: 0 }}
              animate={{ opacity: 1 }}
              exit={{ opacity: 0 }}
              className="fixed inset-0 bg-black/70 flex items-center justify-center z-60"
              onClick={() => setShowAddProvider(false)}
            >
              <motion.div
                initial={{ scale: 0.95, opacity: 0 }}
                animate={{ scale: 1, opacity: 1 }}
                exit={{ scale: 0.95, opacity: 0 }}
                onClick={(e) => e.stopPropagation()}
                className="bg-surface-subtle rounded-lg p-6 w-full max-w-md mx-4 space-y-4"
              >
                <h3 className="text-lg font-semibold">Add Custom Provider</h3>
                <div className="space-y-3">
                  <div>
                    <label className="text-xs text-fg-muted">ID (e.g., ollama)</label>
                    <Input
                      value={newProvider.id || ''}
                      onChange={(e) => setNewProvider((p) => ({ ...p, id: e.target.value }))}
                      placeholder="provider-id"
                    />
                  </div>
                  <div>
                    <label className="text-xs text-fg-muted">Name</label>
                    <Input
                      value={newProvider.name || ''}
                      onChange={(e) => setNewProvider((p) => ({ ...p, name: e.target.value }))}
                      placeholder="My Provider"
                    />
                  </div>
                  <div>
                    <label className="text-xs text-fg-muted">Base URL (OpenAI compatible)</label>
                    <Input
                      value={newProvider.baseUrl || ''}
                      onChange={(e) => setNewProvider((p) => ({ ...p, baseUrl: e.target.value }))}
                      placeholder="http://localhost:11434/v1"
                    />
                  </div>
                </div>
                <div className="flex justify-end gap-2 pt-2">
                  <Button variant="ghost" onClick={() => setShowAddProvider(false)}>
                    Cancel
                  </Button>
                  <Button onClick={handleAddProvider}>
                    Add Provider
                  </Button>
                </div>
              </motion.div>
            </motion.div>
          )}
        </AnimatePresence>

        {/* Add Model Dialog */}
        <AnimatePresence>
          {showAddModel && (
            <motion.div
              initial={{ opacity: 0 }}
              animate={{ opacity: 1 }}
              exit={{ opacity: 0 }}
              className="fixed inset-0 bg-black/70 flex items-center justify-center z-60"
              onClick={() => setShowAddModel(null)}
            >
              <motion.div
                initial={{ scale: 0.95, opacity: 0 }}
                animate={{ scale: 1, opacity: 1 }}
                exit={{ scale: 0.95, opacity: 0 }}
                onClick={(e) => e.stopPropagation()}
                className="bg-surface-subtle rounded-lg p-6 w-full max-w-md mx-4 space-y-4"
              >
                <h3 className="text-lg font-semibold">Add Custom Model</h3>
                <div className="space-y-3">
                  <div>
                    <label className="text-xs text-fg-muted">Model ID</label>
                    <Input
                      value={newModel.id || ''}
                      onChange={(e) => setNewModel((m) => ({ ...m, id: e.target.value }))}
                      placeholder="llama3.2"
                    />
                  </div>
                  <div>
                    <label className="text-xs text-fg-muted">Display Name</label>
                    <Input
                      value={newModel.name || ''}
                      onChange={(e) => setNewModel((m) => ({ ...m, name: e.target.value }))}
                      placeholder="Llama 3.2"
                    />
                  </div>
                </div>
                <div className="flex justify-end gap-2 pt-2">
                  <Button variant="ghost" onClick={() => setShowAddModel(null)}>
                    Cancel
                  </Button>
                  <Button onClick={() => showAddModel && handleAddModel(showAddModel)}>
                    Add Model
                  </Button>
                </div>
              </motion.div>
            </motion.div>
          )}
        </AnimatePresence>

        {/* Provider Editor */}
        {editingProviderId && (
          <ProviderEditor
            providerId={editingProviderId}
            onClose={() => setEditingProviderId(null)}
            onSave={() => {
              setEditingProviderId(null);
              // Clear cached details and reload
              setProviderDetails((prev) => {
                const newDetails = { ...prev };
                delete newDetails[editingProviderId];
                return newDetails;
              });
              loadProviders();
            }}
            responsive={responsive}
          />
        )}
      </motion.div>
    </AnimatePresence>
  );
}
