/**
 * HooksPanel Component
 *
 * Hooks 钩子配置管理面板：显示和编辑所有钩子类型
 */

import { useState, useEffect, useCallback } from 'react';
import {
  X,
  RefreshCw,
  Zap,
  Plus,
  ChevronDown,
  ChevronRight,
  FileEdit,
  FilePlus,
  FileX,
  CheckCircle,
  Trash2,
  Play,
  Edit2,
  AlertCircle,
} 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 { Skeleton } from './Skeleton';
import { HookEditor } from './HookEditor';
import {
  getHooksConfig,
  updateHooksConfig,
  testHookCommand,
  type HookConfig,
  type FileHookConfig,
  type ShellCommandConfig,
} from '../api/client.js';

interface HooksPanelProps {
  onClose: () => void;
  /** 是否启用响应式布局 */
  responsive?: boolean;
}

type HookType = 'file_edited' | 'file_created' | 'file_deleted' | 'session_completed';

interface EditingHook {
  type: HookType;
  pattern?: string; // 仅用于文件钩子
  command?: ShellCommandConfig;
  isNew: boolean;
}

const HOOK_TYPES: { type: HookType; label: string; icon: React.ReactNode; description: string }[] = [
  { type: 'file_edited', label: 'File Edited', icon: <FileEdit size={16} />, description: 'Triggered after a file is edited' },
  { type: 'file_created', label: 'File Created', icon: <FilePlus size={16} />, description: 'Triggered after a file is created' },
  { type: 'file_deleted', label: 'File Deleted', icon: <FileX size={16} />, description: 'Triggered after a file is deleted' },
  { type: 'session_completed', label: 'Session Completed', icon: <CheckCircle size={16} />, description: 'Triggered when a session ends' },
];

export function HooksPanel({ onClose, responsive = false }: HooksPanelProps) {
  // 数据状态
  const [config, setConfig] = useState<HookConfig>({});
  const [expandedTypes, setExpandedTypes] = useState<Set<HookType>>(new Set(['file_edited']));

  // UI 状态
  const [loading, setLoading] = useState(true);
  const [refreshing, setRefreshing] = useState(false);
  const [saving, setSaving] = useState(false);
  const [testingCommand, setTestingCommand] = useState<string | null>(null);

  // 编辑状态
  const [editingHook, setEditingHook] = useState<EditingHook | null>(null);

  // 加载配置
  const loadConfig = useCallback(async (showToast = false) => {
    try {
      const result = await getHooksConfig();
      if (result.success) {
        setConfig(result.data);
        if (showToast) {
          toast.success('Configuration refreshed');
        }
      } else {
        toast.error(result.error || 'Failed to load configuration');
      }
    } catch (err) {
      toast.error(err instanceof Error ? err.message : 'Failed to load configuration');
    }
  }, []);

  // 初始加载
  useEffect(() => {
    setLoading(true);
    loadConfig().finally(() => setLoading(false));
  }, [loadConfig]);

  // 刷新
  const handleRefresh = async () => {
    setRefreshing(true);
    await loadConfig(true);
    setRefreshing(false);
  };

  // 保存配置
  const saveConfig = async (newConfig: HookConfig) => {
    setSaving(true);
    try {
      const result = await updateHooksConfig(newConfig);
      if (result.success) {
        setConfig(result.data);
        toast.success('Configuration saved');
        return true;
      } else {
        toast.error(result.error || 'Failed to save configuration');
        return false;
      }
    } catch (err) {
      toast.error(err instanceof Error ? err.message : 'Failed to save configuration');
      return false;
    } finally {
      setSaving(false);
    }
  };

  // 切换展开
  const toggleExpanded = (type: HookType) => {
    const newExpanded = new Set(expandedTypes);
    if (newExpanded.has(type)) {
      newExpanded.delete(type);
    } else {
      newExpanded.add(type);
    }
    setExpandedTypes(newExpanded);
  };

  // 测试命令
  const handleTestCommand = async (cmd: ShellCommandConfig, id: string) => {
    setTestingCommand(id);
    try {
      const result = await testHookCommand(cmd);
      if (result.success && result.data) {
        if (result.data.success) {
          toast.success(
            <div>
              <div className="font-medium">Command succeeded</div>
              <div className="text-xs text-gray-400 mt-1">
                Exit code: {result.data.exitCode} ({result.data.duration}ms)
              </div>
              {result.data.stdout && (
                <pre className="text-xs bg-gray-900 p-2 rounded mt-2 max-h-32 overflow-auto">
                  {result.data.stdout.slice(0, 500)}
                </pre>
              )}
            </div>
          );
        } else {
          toast.error(
            <div>
              <div className="font-medium">Command failed</div>
              <div className="text-xs text-gray-400 mt-1">
                Exit code: {result.data.exitCode} ({result.data.duration}ms)
              </div>
              {result.data.stderr && (
                <pre className="text-xs bg-gray-900 p-2 rounded mt-2 max-h-32 overflow-auto text-red-400">
                  {result.data.stderr.slice(0, 500)}
                </pre>
              )}
            </div>
          );
        }
      } else {
        toast.error(result.error || 'Test failed');
      }
    } catch (err) {
      toast.error(err instanceof Error ? err.message : 'Test failed');
    } finally {
      setTestingCommand(null);
    }
  };

  // 删除文件钩子的某个 pattern
  const handleDeleteFileHook = async (type: HookType, pattern: string) => {
    if (type === 'session_completed') return;

    const fileHooks = config[type] as FileHookConfig | undefined;
    if (!fileHooks) return;

    const newFileHooks = { ...fileHooks };
    delete newFileHooks[pattern];

    const newConfig = { ...config, [type]: newFileHooks };
    await saveConfig(newConfig);
  };

  // 删除 session_completed 的某个命令
  const handleDeleteSessionHook = async (index: number) => {
    const commands = config.session_completed || [];
    const newCommands = commands.filter((_, i) => i !== index);
    const newConfig = { ...config, session_completed: newCommands };
    await saveConfig(newConfig);
  };

  // 打开编辑器 - 文件钩子
  const openFileHookEditor = (type: HookType, pattern?: string, commands?: ShellCommandConfig[]) => {
    setEditingHook({
      type,
      pattern,
      command: commands?.[0],
      isNew: !pattern,
    });
  };

  // 打开编辑器 - Session 钩子
  const openSessionHookEditor = (command?: ShellCommandConfig, index?: number) => {
    setEditingHook({
      type: 'session_completed',
      pattern: index !== undefined ? String(index) : undefined,
      command,
      isNew: index === undefined,
    });
  };

  // 保存编辑的钩子
  const handleSaveHook = async (type: HookType, pattern: string, commands: ShellCommandConfig[]) => {
    let newConfig: HookConfig;

    if (type === 'session_completed') {
      // Session hook
      const existingCommands = [...(config.session_completed || [])];
      const index = editingHook?.pattern !== undefined ? parseInt(editingHook.pattern) : -1;

      if (index >= 0 && index < existingCommands.length) {
        // 更新现有命令
        existingCommands[index] = commands[0];
      } else {
        // 添加新命令
        existingCommands.push(commands[0]);
      }

      newConfig = { ...config, session_completed: existingCommands };
    } else {
      // File hook
      const fileHooks = { ...(config[type] as FileHookConfig || {}) };

      // 如果是重命名 pattern
      if (editingHook?.pattern && editingHook.pattern !== pattern) {
        delete fileHooks[editingHook.pattern];
      }

      fileHooks[pattern] = commands;
      newConfig = { ...config, [type]: fileHooks };
    }

    const success = await saveConfig(newConfig);
    if (success) {
      setEditingHook(null);
    }
  };

  // 统计
  const totalHooks = Object.values(config).reduce((sum, hooks) => {
    if (Array.isArray(hooks)) {
      return sum + hooks.length;
    }
    if (hooks && typeof hooks === 'object') {
      return sum + Object.keys(hooks).length;
    }
    return sum;
  }, 0);

  // Loading 骨架屏
  const LoadingSkeleton = () => (
    <div className="space-y-3 p-4">
      {[1, 2, 3, 4].map((i) => (
        <div key={i} className="bg-gray-900/50 rounded-lg p-3">
          <div className="flex items-center gap-3">
            <Skeleton className="h-4 w-4" />
            <Skeleton className="h-4 w-32" />
            <Skeleton className="h-4 w-16 ml-auto" />
          </div>
        </div>
      ))}
    </div>
  );

  // 渲染文件钩子内容
  const renderFileHooks = (type: HookType) => {
    const hooks = config[type] as FileHookConfig | undefined;
    const patterns = Object.keys(hooks || {});

    if (patterns.length === 0) {
      return (
        <div className="text-xs text-gray-500 py-2 px-3">
          No hooks configured
        </div>
      );
    }

    return (
      <div className="space-y-2">
        {patterns.map((pattern) => {
          const commands = hooks![pattern];
          const cmdId = `${type}-${pattern}`;

          return (
            <div key={pattern} className="bg-gray-800/50 rounded p-2">
              <div className="flex items-center justify-between">
                <code className="text-xs font-mono text-blue-400">{pattern}</code>
                <div className="flex items-center gap-1">
                  <Button
                    variant="ghost"
                    size="sm"
                    onClick={() => openFileHookEditor(type, pattern, commands)}
                    className="h-6 w-6 p-0"
                    title="Edit"
                  >
                    <Edit2 size={12} />
                  </Button>
                  <Button
                    variant="ghost"
                    size="sm"
                    onClick={() => handleDeleteFileHook(type, pattern)}
                    className="h-6 w-6 p-0 text-red-400 hover:text-red-300"
                    title="Delete"
                  >
                    <Trash2 size={12} />
                  </Button>
                </div>
              </div>
              <div className="mt-1 space-y-1">
                {commands.map((cmd, idx) => (
                  <div key={idx} className="flex items-center justify-between text-xs">
                    <code className="font-mono text-gray-400 truncate flex-1">
                      {cmd.command.join(' ')}
                    </code>
                    <Button
                      variant="ghost"
                      size="sm"
                      onClick={() => handleTestCommand(cmd, `${cmdId}-${idx}`)}
                      disabled={testingCommand === `${cmdId}-${idx}`}
                      className="h-5 px-1.5 text-green-400 hover:text-green-300"
                      title="Test"
                    >
                      {testingCommand === `${cmdId}-${idx}` ? (
                        <RefreshCw size={10} className="animate-spin" />
                      ) : (
                        <Play size={10} />
                      )}
                    </Button>
                  </div>
                ))}
              </div>
            </div>
          );
        })}
      </div>
    );
  };

  // 渲染 session hooks
  const renderSessionHooks = () => {
    const commands = config.session_completed || [];

    if (commands.length === 0) {
      return (
        <div className="text-xs text-gray-500 py-2 px-3">
          No hooks configured
        </div>
      );
    }

    return (
      <div className="space-y-2">
        {commands.map((cmd, idx) => {
          const cmdId = `session-${idx}`;
          return (
            <div key={idx} className="bg-gray-800/50 rounded p-2 flex items-center justify-between">
              <code className="text-xs font-mono text-gray-400 truncate flex-1">
                {cmd.command.join(' ')}
              </code>
              <div className="flex items-center gap-1">
                <Button
                  variant="ghost"
                  size="sm"
                  onClick={() => handleTestCommand(cmd, cmdId)}
                  disabled={testingCommand === cmdId}
                  className="h-6 px-1.5 text-green-400 hover:text-green-300"
                  title="Test"
                >
                  {testingCommand === cmdId ? (
                    <RefreshCw size={10} className="animate-spin" />
                  ) : (
                    <Play size={10} />
                  )}
                </Button>
                <Button
                  variant="ghost"
                  size="sm"
                  onClick={() => openSessionHookEditor(cmd, idx)}
                  className="h-6 w-6 p-0"
                  title="Edit"
                >
                  <Edit2 size={12} />
                </Button>
                <Button
                  variant="ghost"
                  size="sm"
                  onClick={() => handleDeleteSessionHook(idx)}
                  className="h-6 w-6 p-0 text-red-400 hover:text-red-300"
                  title="Delete"
                >
                  <Trash2 size={12} />
                </Button>
              </div>
            </div>
          );
        })}
      </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-gray-800 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-gray-700',
                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-gray-600 rounded-full md:hidden" />
              )}
              <div className={cn(responsive && 'mt-2 md:mt-0')}>
                <h2 className="text-lg font-semibold flex items-center gap-2">
                  <Zap size={20} className="text-yellow-400" />
                  Hooks Configuration
                </h2>
                <p className="text-xs text-gray-500">
                  {totalHooks} hooks configured
                </p>
              </div>
              <div className="flex items-center gap-2">
                <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>

            {/* Content */}
            <div className="flex-1 overflow-y-auto">
              {loading ? (
                <LoadingSkeleton />
              ) : (
                <motion.div
                  initial={{ opacity: 0 }}
                  animate={{ opacity: 1 }}
                  className={cn('space-y-2', responsive ? 'p-4' : 'p-4')}
                >
                  {HOOK_TYPES.map(({ type, label, icon, description }) => {
                    const isExpanded = expandedTypes.has(type);
                    const isFileHook = type !== 'session_completed';
                    const hookCount = isFileHook
                      ? Object.keys((config[type] as FileHookConfig) || {}).length
                      : (config.session_completed || []).length;

                    return (
                      <motion.div
                        key={type}
                        layout
                        className="bg-gray-900/50 rounded-lg overflow-hidden"
                      >
                        {/* Type Header */}
                        <div
                          className={cn(
                            'flex items-center gap-3 p-3',
                            'hover:bg-gray-900/80 transition-colors cursor-pointer'
                          )}
                          onClick={() => toggleExpanded(type)}
                        >
                          <button className="text-gray-500 hover:text-gray-300">
                            {isExpanded ? <ChevronDown size={16} /> : <ChevronRight size={16} />}
                          </button>

                          <div className="text-primary-400">{icon}</div>

                          <div className="flex-1 min-w-0">
                            <div className="flex items-center gap-2">
                              <span className="font-medium text-gray-200">{label}</span>
                              {hookCount > 0 && (
                                <span className="text-xs bg-gray-700 px-1.5 py-0.5 rounded">
                                  {hookCount}
                                </span>
                              )}
                            </div>
                            <div className="text-xs text-gray-500">{description}</div>
                          </div>

                          <Button
                            variant="ghost"
                            size="sm"
                            onClick={(e) => {
                              e.stopPropagation();
                              if (isFileHook) {
                                openFileHookEditor(type);
                              } else {
                                openSessionHookEditor();
                              }
                            }}
                            className="text-primary-400 hover:text-primary-300"
                          >
                            <Plus size={14} className="mr-1" />
                            Add
                          </Button>
                        </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-gray-700/50">
                                {isFileHook ? renderFileHooks(type) : renderSessionHooks()}
                              </div>
                            </motion.div>
                          )}
                        </AnimatePresence>
                      </motion.div>
                    );
                  })}
                </motion.div>
              )}
            </div>

            {/* Footer */}
            <div
              className={cn(
                'border-t border-gray-700 text-xs text-gray-500 px-4 py-3 flex items-start gap-2',
                responsive && 'safe-area-pb'
              )}
            >
              <AlertCircle size={14} className="flex-shrink-0 mt-0.5 text-yellow-500" />
              <span>
                Commands are executed in your project directory. Use caution with destructive operations.
              </span>
            </div>
          </motion.div>
        </motion.div>
      </AnimatePresence>

      {/* Hook Editor Modal */}
      {editingHook && (
        <HookEditor
          type={editingHook.type}
          pattern={editingHook.pattern}
          commands={editingHook.command ? [editingHook.command] : []}
          isNew={editingHook.isNew}
          onSave={handleSaveHook}
          onCancel={() => setEditingHook(null)}
          onTest={handleTestCommand}
          saving={saving}
          responsive={responsive}
        />
      )}
    </>
  );
}
