/**
 * Hooks Route 测试
 *
 * 测试 Hooks 配置管理 REST API 端点
 */

import { describe, it, expect, beforeEach, vi } from 'vitest';
import { Hono } from 'hono';

// Create mock hooks module
const mockHooksModule = vi.hoisted(() => ({
  loadProjectConfig: vi.fn(),
  loadHookConfig: vi.fn(),
  getConfigFilePath: vi.fn(),
  createDefaultConfig: vi.fn(),
}));

// Track if module should be available
let moduleAvailable = true;

vi.mock('@ai-assistant/core', () => {
  if (!moduleAvailable) {
    throw new Error('Module not found');
  }
  return mockHooksModule;
});

vi.mock('../../../src/routes/config.js', () => ({
  getConfig: vi.fn(() => ({ workdir: '/test/workdir' })),
}));

// Mock fs/promises
vi.mock('fs/promises', () => ({
  readFile: vi.fn().mockResolvedValue('{}'),
  writeFile: vi.fn().mockResolvedValue(undefined),
}));

import { hooksRouter } from '../../../src/routes/hooks.js';

// Create test app
const app = new Hono();
app.route('/hooks', hooksRouter);

describe('Hooks Route', () => {
  beforeEach(() => {
    vi.clearAllMocks();
    moduleAvailable = true;
    mockHooksModule.loadHookConfig.mockResolvedValue(null);
    mockHooksModule.getConfigFilePath.mockResolvedValue('/test/workdir/.ai-assistant.json');
  });

  describe('GET /hooks/config - 获取完整钩子配置', () => {
    it('返回钩子配置', async () => {
      mockHooksModule.loadHookConfig.mockResolvedValue({
        file_edited: { '*.ts': [{ command: ['npx', 'prettier', '--write'] }] },
        session_completed: [],
      });

      const res = await app.request('/hooks/config');
      const json = await res.json();

      expect(res.status).toBe(200);
      expect(json.success).toBe(true);
      expect(json.data.file_edited).toBeDefined();
    });

    it('无配置时返回默认空对象', async () => {
      mockHooksModule.loadHookConfig.mockResolvedValue(null);

      const res = await app.request('/hooks/config');
      const json = await res.json();

      expect(res.status).toBe(200);
      expect(json.data.file_edited).toEqual({});
      expect(json.data.session_completed).toEqual([]);
    });
  });

  describe('PUT /hooks/config - 更新完整钩子配置', () => {
    it('更新成功', async () => {
      const res = await app.request('/hooks/config', {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          file_edited: { '*.ts': [{ command: ['echo', 'edited'] }] },
        }),
      });
      const json = await res.json();

      expect(res.status).toBe(200);
      expect(json.success).toBe(true);
    });
  });

  describe('GET /hooks/file-edited - 获取 file_edited 钩子', () => {
    it('返回 file_edited 配置', async () => {
      mockHooksModule.loadHookConfig.mockResolvedValue({
        file_edited: { '*.ts': [{ command: ['npx', 'prettier', '--write'] }] },
      });

      const res = await app.request('/hooks/file-edited');
      const json = await res.json();

      expect(res.status).toBe(200);
      expect(json.success).toBe(true);
      expect(json.data['*.ts']).toBeDefined();
    });

    it('无配置时返回空对象', async () => {
      const res = await app.request('/hooks/file-edited');
      const json = await res.json();

      expect(res.status).toBe(200);
      expect(json.data).toEqual({});
    });
  });

  describe('PUT /hooks/file-edited - 更新 file_edited 钩子', () => {
    it('更新成功', async () => {
      const res = await app.request('/hooks/file-edited', {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          '*.ts': [{ command: ['npx', 'eslint', '--fix'] }],
        }),
      });
      const json = await res.json();

      expect(res.status).toBe(200);
      expect(json.success).toBe(true);
    });
  });

  describe('GET /hooks/file-created - 获取 file_created 钩子', () => {
    it('返回 file_created 配置', async () => {
      mockHooksModule.loadHookConfig.mockResolvedValue({
        file_created: { '*.tsx': [{ command: ['echo', 'new file'] }] },
      });

      const res = await app.request('/hooks/file-created');
      const json = await res.json();

      expect(res.status).toBe(200);
      expect(json.success).toBe(true);
    });

    it('无配置时返回空对象', async () => {
      const res = await app.request('/hooks/file-created');
      const json = await res.json();

      expect(res.status).toBe(200);
      expect(json.data).toEqual({});
    });
  });

  describe('PUT /hooks/file-created - 更新 file_created 钩子', () => {
    it('更新成功', async () => {
      const res = await app.request('/hooks/file-created', {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          '*.tsx': [{ command: ['echo', 'created'] }],
        }),
      });
      const json = await res.json();

      expect(res.status).toBe(200);
      expect(json.success).toBe(true);
    });
  });

  describe('GET /hooks/file-deleted - 获取 file_deleted 钩子', () => {
    it('返回 file_deleted 配置', async () => {
      mockHooksModule.loadHookConfig.mockResolvedValue({
        file_deleted: { '*.log': [{ command: ['echo', 'deleted'] }] },
      });

      const res = await app.request('/hooks/file-deleted');
      const json = await res.json();

      expect(res.status).toBe(200);
      expect(json.success).toBe(true);
    });

    it('无配置时返回空对象', async () => {
      const res = await app.request('/hooks/file-deleted');
      const json = await res.json();

      expect(res.status).toBe(200);
      expect(json.data).toEqual({});
    });
  });

  describe('PUT /hooks/file-deleted - 更新 file_deleted 钩子', () => {
    it('更新成功', async () => {
      const res = await app.request('/hooks/file-deleted', {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          '*.tmp': [{ command: ['echo', 'cleaned'] }],
        }),
      });
      const json = await res.json();

      expect(res.status).toBe(200);
      expect(json.success).toBe(true);
    });
  });

  describe('GET /hooks/session-completed - 获取 session_completed 钩子', () => {
    it('返回 session_completed 配置', async () => {
      mockHooksModule.loadHookConfig.mockResolvedValue({
        session_completed: [{ command: ['echo', 'session done'] }],
      });

      const res = await app.request('/hooks/session-completed');
      const json = await res.json();

      expect(res.status).toBe(200);
      expect(json.success).toBe(true);
      expect(json.data).toHaveLength(1);
    });

    it('无配置时返回空数组', async () => {
      const res = await app.request('/hooks/session-completed');
      const json = await res.json();

      expect(res.status).toBe(200);
      expect(json.data).toEqual([]);
    });
  });

  describe('PUT /hooks/session-completed - 更新 session_completed 钩子', () => {
    it('更新成功', async () => {
      const res = await app.request('/hooks/session-completed', {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify([{ command: ['echo', 'completed'] }]),
      });
      const json = await res.json();

      expect(res.status).toBe(200);
      expect(json.success).toBe(true);
    });
  });

  describe('POST /hooks/test - 测试执行钩子命令', () => {
    it('执行简单命令', async () => {
      const res = await app.request('/hooks/test', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          command: ['echo', 'test'],
        }),
      });
      const json = await res.json();

      expect(res.status).toBe(200);
      expect(json.success).toBe(true);
      expect(json.data).toHaveProperty('exitCode');
      expect(json.data).toHaveProperty('duration');
    });

    it('无效命令配置返回 400', async () => {
      const res = await app.request('/hooks/test', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          command: [],
        }),
      });
      const json = await res.json();

      expect(res.status).toBe(400);
      expect(json.success).toBe(false);
      expect(json.error).toContain('Invalid command configuration');
    });

    it('命令非数组返回 400', async () => {
      const res = await app.request('/hooks/test', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          command: 'echo test',
        }),
      });
      const json = await res.json();

      expect(res.status).toBe(400);
      expect(json.success).toBe(false);
    });

    it('支持超时配置', async () => {
      const res = await app.request('/hooks/test', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          command: ['echo', 'quick'],
          timeout: 5000,
        }),
      });
      const json = await res.json();

      expect(res.status).toBe(200);
      expect(json.success).toBe(true);
    });

    it('支持环境变量', async () => {
      const res = await app.request('/hooks/test', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          command: ['echo', '$TEST_VAR'],
          environment: { TEST_VAR: 'hello' },
        }),
      });
      const json = await res.json();

      expect(res.status).toBe(200);
      expect(json.success).toBe(true);
    });
  });
});
