/**
 * 配置加载器实现
 *
 * 提供JSON配置文件的加载、验证和热加载监听功能
 * 符合<100ms加载性能要求
 */

import * as fs from 'fs';
import * as path from 'path';
import {
  LoadResult,
  ConfigFile,
  Account,
  CredentialManagerError,
  ErrorType
} from '@/core/types';
import { createAccountFromConfig } from '@/core/Account';

/**
 * 配置加载器接口
 */
export interface IConfigLoader {
  loadConfig(filePath: string): Promise<LoadResult>;
  watchConfig(filePath: string, callback: (accounts: Account[]) => void): void;
  stopWatching(): void;
}

/**
 * 配置加载器实现
 */
export class ConfigLoader implements IConfigLoader {
  private watcher?: fs.FSWatcher | undefined;
  private currentWatchPath?: string | undefined;
  private debounceTimer?: NodeJS.Timeout | undefined;
  private isWatching = false;

  /**
   * 加载配置文件
   */
  public async loadConfig(filePath: string): Promise<LoadResult> {
    const startTime = Date.now();
    const errors: string[] = [];

    try {
      // 验证文件路径
      if (!filePath || typeof filePath !== 'string') {
        throw new CredentialManagerError(
          'File path must be a valid string',
          ErrorType.CONFIG_LOAD_ERROR,
          { filePath }
        );
      }

      // 检查文件是否存在
      if (!fs.existsSync(filePath)) {
        throw new CredentialManagerError(
          `Configuration file not found: ${filePath}`,
          ErrorType.CONFIG_LOAD_ERROR,
          { filePath }
        );
      }

      // 读取文件内容
      const fileContent = await fs.promises.readFile(filePath, 'utf-8');

      // 解析JSON
      let configData: ConfigFile;
      try {
        configData = JSON.parse(fileContent);
      } catch (parseError) {
        throw new CredentialManagerError(
          `Invalid JSON format in configuration file: ${(parseError as Error).message}`,
          ErrorType.CONFIG_LOAD_ERROR,
          { filePath, parseError: (parseError as Error).message }
        );
      }

      // 验证配置结构
      this.validateConfigStructure(configData);

      // 加载账户
      const accounts: Account[] = [];

      if (configData.accounts && Array.isArray(configData.accounts)) {
        for (let i = 0; i < configData.accounts.length; i++) {
          try {
            const accountConfig = configData.accounts[i];
            const account = createAccountFromConfig(accountConfig);
            accounts.push(account);
          } catch (error) {
            const errorMessage = `Failed to load account at index ${i}: ${(error as Error).message}`;
            errors.push(errorMessage);

            if (error instanceof CredentialManagerError) {
              // 严重错误，停止加载
              if (error.type === ErrorType.VALIDATION_ERROR) {
                continue; // 跳过无效账户，继续加载其他账户
              }
            }
          }
        }
      }

      const loadTime = Date.now() - startTime;

      // 检查是否有任何成功加载的账户
      if (accounts.length === 0 && configData.accounts && configData.accounts.length > 0) {
        return {
          success: false,
          accounts: [],
          errors: errors.length > 0 ? errors : ['No valid accounts found in configuration'],
          loadTime,
        };
      }

      return {
        success: true,
        accounts,
        errors: errors.length > 0 ? errors : undefined,
        loadTime,
      };

    } catch (error) {
      const loadTime = Date.now() - startTime;

      if (error instanceof CredentialManagerError) {
        errors.push(error.message);
      } else {
        errors.push(`Unexpected error: ${(error as Error).message}`);
      }

      return {
        success: false,
        accounts: [],
        errors,
        loadTime,
      };
    }
  }

  /**
   * 开始监听配置文件变更
   */
  public watchConfig(filePath: string, callback: (accounts: Account[]) => void): void {
    // 停止之前的监听
    this.stopWatching();

    try {
      // 验证文件路径
      if (!filePath || typeof filePath !== 'string') {
        throw new CredentialManagerError(
          'File path must be a valid string',
          ErrorType.CONFIG_LOAD_ERROR,
          { filePath }
        );
      }

      // 确保文件存在
      if (!fs.existsSync(filePath)) {
        throw new CredentialManagerError(
          `Configuration file not found: ${filePath}`,
          ErrorType.CONFIG_LOAD_ERROR,
          { filePath }
        );
      }

      this.currentWatchPath = filePath;
      this.isWatching = true;

      // 创建文件监听器
      this.watcher = fs.watch(filePath, { persistent: true }, (eventType, filename) => {
        // 只响应文件内容变更
        if (eventType === 'change') {
          this.handleFileChange(callback);
        }
      });

      // 处理监听器错误
      this.watcher.on('error', (error) => {
        console.error('File watcher error:', error);
        this.stopWatching();
      });

    } catch (error) {
      throw new CredentialManagerError(
        `Failed to start watching config file: ${(error as Error).message}`,
        ErrorType.CONFIG_LOAD_ERROR,
        { filePath, error: (error as Error).message }
      );
    }
  }

  /**
   * 停止监听配置文件
   */
  public stopWatching(): void {
    if (this.watcher) {
      this.watcher.close();
      this.watcher = undefined;
    }

    if (this.debounceTimer) {
      clearTimeout(this.debounceTimer);
      this.debounceTimer = undefined;
    }

    this.currentWatchPath = undefined;
    this.isWatching = false;
  }

  /**
   * 处理文件变更（带防抖）
   */
  private handleFileChange(callback: (accounts: Account[]) => void): void {
    // 清除之前的定时器
    if (this.debounceTimer) {
      clearTimeout(this.debounceTimer);
    }

    // 设置防抖定时器
    this.debounceTimer = setTimeout(async () => {
      try {
        if (this.currentWatchPath && this.isWatching) {
          const result = await this.loadConfig(this.currentWatchPath);

          if (result.success) {
            callback(result.accounts);
          } else {
            console.error('Failed to reload configuration:', result.errors);
          }
        }
      } catch (error) {
        console.error('Error handling file change:', error);
      }
    }, 100); // 100ms防抖延迟
  }

  /**
   * 验证配置文件结构
   */
  private validateConfigStructure(config: any): void {
    if (!config || typeof config !== 'object') {
      throw new CredentialManagerError(
        'Configuration must be a valid object',
        ErrorType.VALIDATION_ERROR,
        { config }
      );
    }

    // 验证版本字段
    if (!config.version || typeof config.version !== 'string') {
      throw new CredentialManagerError(
        'Configuration must include a valid version string',
        ErrorType.VALIDATION_ERROR,
        { version: config.version }
      );
    }

    // 验证版本格式
    const versionPattern = /^\d+\.\d+$/;
    if (!versionPattern.test(config.version)) {
      throw new CredentialManagerError(
        'Version must be in format "major.minor" (e.g., "1.0")',
        ErrorType.VALIDATION_ERROR,
        { version: config.version }
      );
    }

    // 验证accounts字段
    if (config.accounts !== undefined) {
      if (!Array.isArray(config.accounts)) {
        throw new CredentialManagerError(
          'Accounts must be an array',
          ErrorType.VALIDATION_ERROR,
          { accounts: config.accounts }
        );
      }
    }
  }

  /**
   * 获取当前监听状态
   */
  public getWatchStatus(): { isWatching: boolean; watchPath?: string } {
    const result: { isWatching: boolean; watchPath?: string } = {
      isWatching: this.isWatching,
    };

    if (this.currentWatchPath) {
      result.watchPath = this.currentWatchPath;
    }

    return result;
  }

  /**
   * 验证配置文件格式（静态方法）
   */
  public static async validateConfigFile(filePath: string): Promise<{ valid: boolean; errors: string[] }> {
    const errors: string[] = [];

    try {
      if (!fs.existsSync(filePath)) {
        errors.push(`File not found: ${filePath}`);
        return { valid: false, errors };
      }

      const content = await fs.promises.readFile(filePath, 'utf-8');

      try {
        const config = JSON.parse(content);

        // 基本结构验证
        if (!config.version) {
          errors.push('Missing version field');
        }

        if (!Array.isArray(config.accounts)) {
          errors.push('Accounts field must be an array');
        }

        // 验证每个账户的基本结构
        if (config.accounts) {
          config.accounts.forEach((account: any, index: number) => {
            if (!account.id) {
              errors.push(`Account at index ${index} missing id field`);
            }
            if (!account.platform) {
              errors.push(`Account at index ${index} missing platform field`);
            }
            if (!account.credentials) {
              errors.push(`Account at index ${index} missing credentials field`);
            }
          });
        }

      } catch (parseError) {
        errors.push(`Invalid JSON: ${(parseError as Error).message}`);
      }

    } catch (error) {
      errors.push(`File read error: ${(error as Error).message}`);
    }

    return {
      valid: errors.length === 0,
      errors,
    };
  }
}