/**
 * Hook 配置加载器
 *
 * 从项目配置文件加载 hook 配置
 * 支持 .ai-assistant.json, .ai-assistant.jsonc, ai-assistant.config.json 等格式
 */

import * as fs from 'fs/promises';
import * as path from 'path';
import type { HookConfig, ShellCommandConfig, FileHookConfig } from './types.js';

// 支持的配置文件名
const CONFIG_FILE_NAMES = [
  '.ai-assistant.json',
  '.ai-assistant.jsonc',
  'ai-assistant.config.json',
  '.ai-assistantrc',
  '.ai-assistantrc.json',
];

/**
 * 完整的配置文件结构
 */
export interface ProjectConfig {
  /** Hook 配置 */
  hooks?: HookConfig;
  /** 插件列表 */
  plugins?: string[];
  /** 其他配置... */
  [key: string]: unknown;
}

/**
 * 移除 JSON 中的注释（支持 JSONC 格式）
 */
function stripJsonComments(jsonString: string): string {
  // 移除单行注释 // ...
  let result = jsonString.replace(/\/\/.*$/gm, '');
  // 移除多行注释 /* ... */
  result = result.replace(/\/\*[\s\S]*?\*\//g, '');
  return result;
}

/**
 * 解析 JSON 文件（支持 JSONC）
 */
async function parseJsonFile(filePath: string): Promise<ProjectConfig | null> {
  try {
    const content = await fs.readFile(filePath, 'utf-8');
    const cleanContent = stripJsonComments(content);
    return JSON.parse(cleanContent);
  } catch {
    return null;
  }
}

/**
 * 在目录中查找配置文件
 */
async function findConfigFile(directory: string): Promise<string | null> {
  for (const fileName of CONFIG_FILE_NAMES) {
    const filePath = path.join(directory, fileName);
    try {
      await fs.access(filePath);
      return filePath;
    } catch {
      // 文件不存在，继续查找
    }
  }
  return null;
}

/**
 * 验证 ShellCommandConfig
 */
function validateShellCommandConfig(config: unknown): config is ShellCommandConfig {
  if (typeof config !== 'object' || config === null) return false;
  const obj = config as Record<string, unknown>;

  // command 必须是非空字符串数组
  if (!Array.isArray(obj.command) || obj.command.length === 0) return false;
  if (!obj.command.every((c) => typeof c === 'string')) return false;

  // environment 如果存在，必须是对象
  if (obj.environment !== undefined) {
    if (typeof obj.environment !== 'object' || obj.environment === null) return false;
    const env = obj.environment as Record<string, unknown>;
    if (!Object.values(env).every((v) => typeof v === 'string')) return false;
  }

  // timeout 如果存在，必须是正数
  if (obj.timeout !== undefined) {
    if (typeof obj.timeout !== 'number' || obj.timeout <= 0) return false;
  }

  // cwd 如果存在，必须是字符串
  if (obj.cwd !== undefined) {
    if (typeof obj.cwd !== 'string') return false;
  }

  return true;
}

/**
 * 验证 FileHookConfig
 */
function validateFileHookConfig(config: unknown): config is FileHookConfig {
  if (typeof config !== 'object' || config === null) return false;
  const obj = config as Record<string, unknown>;

  for (const [pattern, commands] of Object.entries(obj)) {
    // pattern 必须是非空字符串
    if (typeof pattern !== 'string' || pattern.length === 0) return false;

    // commands 必须是 ShellCommandConfig 数组
    if (!Array.isArray(commands)) return false;
    if (!commands.every(validateShellCommandConfig)) return false;
  }

  return true;
}

/**
 * 验证 HookConfig
 */
function validateHookConfig(config: unknown): config is HookConfig {
  if (typeof config !== 'object' || config === null) return false;
  const obj = config as Record<string, unknown>;

  // file_edited
  if (obj.file_edited !== undefined) {
    if (!validateFileHookConfig(obj.file_edited)) return false;
  }

  // file_created
  if (obj.file_created !== undefined) {
    if (!validateFileHookConfig(obj.file_created)) return false;
  }

  // file_deleted
  if (obj.file_deleted !== undefined) {
    if (!validateFileHookConfig(obj.file_deleted)) return false;
  }

  // session_completed
  if (obj.session_completed !== undefined) {
    if (!Array.isArray(obj.session_completed)) return false;
    if (!obj.session_completed.every(validateShellCommandConfig)) return false;
  }

  return true;
}

/**
 * 加载项目配置
 */
export async function loadProjectConfig(directory: string): Promise<ProjectConfig | null> {
  const configPath = await findConfigFile(directory);
  if (!configPath) return null;

  const config = await parseJsonFile(configPath);
  return config;
}

/**
 * 加载 Hook 配置
 */
export async function loadHookConfig(directory: string): Promise<HookConfig | null> {
  const projectConfig = await loadProjectConfig(directory);
  if (!projectConfig?.hooks) return null;

  // 验证配置
  if (!validateHookConfig(projectConfig.hooks)) {
    console.warn('Invalid hook configuration in project config file');
    return null;
  }

  return projectConfig.hooks;
}

/**
 * 加载插件列表
 */
export async function loadPluginList(directory: string): Promise<string[]> {
  const projectConfig = await loadProjectConfig(directory);
  if (!projectConfig?.plugins) return [];

  // 验证插件列表
  if (!Array.isArray(projectConfig.plugins)) return [];
  if (!projectConfig.plugins.every((p) => typeof p === 'string')) return [];

  return projectConfig.plugins;
}

/**
 * 创建默认配置文件
 */
export async function createDefaultConfig(directory: string): Promise<void> {
  const configPath = path.join(directory, '.ai-assistant.json');

  const defaultConfig: ProjectConfig = {
    hooks: {
      file_edited: {
        '*.ts': [
          {
            command: ['npx', 'tsc', '--noEmit'],
            timeout: 30000,
          },
        ],
        '*.{js,jsx,ts,tsx}': [
          {
            command: ['npx', 'eslint', '--fix'],
            timeout: 30000,
          },
        ],
      },
      file_created: {},
      file_deleted: {},
      session_completed: [],
    },
    plugins: [],
  };

  await fs.writeFile(configPath, JSON.stringify(defaultConfig, null, 2));
}

/**
 * 获取配置文件路径（如果存在）
 */
export async function getConfigFilePath(directory: string): Promise<string | null> {
  return findConfigFile(directory);
}
