/**
 * 统一配置管理服务
 *
 * 功能描述：
 * - 统一配置文件管理：只维护一个配置文件
 * - 智能同步机制：远程可用时自动更新本地配置
 * - 自动备份策略：更新前自动备份旧配置
 * - 离线容错能力：远程不可用时使用最后一次成功的配置
 *
 * 工作流程：
 * 1. 启动时加载本地配置文件（如不存在则创建默认配置）
 * 2. 尝试连接Zulip服务器获取最新数据
 * 3. 如果成功：备份旧配置 → 更新配置文件 → 缓存新配置
 * 4. 如果失败：使用现有本地配置 → 记录错误日志
 * 5. 定期重试远程同步（可配置间隔）
 *
 * 最近修改：
 * - 2026-01-12: 代码规范优化 - 修正注释规范和修改记录格式 (修改者: moyin)
 * - 2026-01-12: 重构为统一配置管理模式 (修改者: moyin)
 *
 * @author moyin
 * @version 2.0.1
 * @since 2026-01-12
 * @lastModified 2026-01-12
 */

import { Injectable, Logger, OnModuleInit } from '@nestjs/common';
import { ConfigManagerService } from './config_manager.service';
import axios from 'axios';
import * as fs from 'fs';
import * as path from 'path';

/**
 * Zulip Stream接口
 */
interface ZulipStream {
  stream_id: number;
  name: string;
  description: string;
  invite_only: boolean;
  is_web_public: boolean;
  stream_post_policy: number;
  message_retention_days: number | null;
  history_public_to_subscribers: boolean;
  first_message_id: number | null;
  is_announcement_only: boolean;
}

/**
 * Zulip Topic接口
 */
interface ZulipTopic {
  name: string;
  max_id: number;
}

/**
 * 配置同步结果接口
 */
interface ConfigSyncResult {
  success: boolean;
  source: 'remote' | 'local' | 'default';
  mapCount: number;
  objectCount: number;
  error?: string;
  lastUpdated: Date;
  backupCreated?: boolean;
}

/**
 * 统一配置管理服务类
 *
 * 核心理念：
 * - 单一配置文件：只维护一个 map-config.json
 * - 智能同步：远程可用时自动更新本地
 * - 自动备份：更新前创建备份文件
 * - 离线容错：远程不可用时使用本地配置
 */
@Injectable()
export class DynamicConfigManagerService implements OnModuleInit {
  private readonly logger = new Logger(DynamicConfigManagerService.name);
  private serverUrl: string;
  private botEmail: string;
  private apiKey: string;
  private authHeader: string;
  private lastSyncTime: Date | null = null;
  private configCache: any = null;
  private readonly SYNC_INTERVAL = 30 * 60 * 1000; // 30分钟同步间隔
  private readonly CONFIG_DIR = path.join(process.cwd(), 'config', 'zulip');
  private readonly CONFIG_FILE = path.join(this.CONFIG_DIR, 'map-config.json');
  private readonly BACKUP_DIR = path.join(this.CONFIG_DIR, 'backups');
  private syncTimer: NodeJS.Timeout | null = null;

  constructor(private readonly staticConfigManager: ConfigManagerService) {
    // 从环境变量读取Zulip配置
    this.serverUrl = (process.env.ZULIP_SERVER_URL || '').replace(/\/$/, '');
    this.botEmail = process.env.ZULIP_BOT_EMAIL || '';
    this.apiKey = process.env.ZULIP_BOT_API_KEY || '';

    if (this.serverUrl && this.botEmail && this.apiKey) {
      const credentials = Buffer.from(`${this.botEmail}:${this.apiKey}`).toString('base64');
      this.authHeader = `Basic ${credentials}`;
    }

    this.logger.log('统一配置管理器初始化完成', {
      hasZulipCredentials: !!(this.serverUrl && this.botEmail && this.apiKey),
      configFile: this.CONFIG_FILE,
    });
  }

  async onModuleInit() {
    // 确保目录存在
    this.ensureDirectories();

    // 初始化配置
    await this.initializeConfig();

    // 启动定期同步
    this.startPeriodicSync();
  }

  /**
   * 确保必要的目录存在
   */
  private ensureDirectories(): void {
    if (!fs.existsSync(this.CONFIG_DIR)) {
      fs.mkdirSync(this.CONFIG_DIR, { recursive: true });
    }
    if (!fs.existsSync(this.BACKUP_DIR)) {
      fs.mkdirSync(this.BACKUP_DIR, { recursive: true });
    }
  }

  /**
   * 初始化配置
   */
  private async initializeConfig(): Promise<void> {
    this.logger.log('开始初始化配置');

    try {
      // 1. 加载本地配置文件
      const localConfig = this.loadLocalConfig();

      // 2. 尝试从远程同步
      const syncResult = await this.syncFromRemote();

      if (syncResult.success) {
        this.logger.log('配置初始化完成：使用远程同步数据', {
          mapCount: syncResult.mapCount,
          objectCount: syncResult.objectCount,
        });
        this.configCache = await this.loadLocalConfig();
      } else {
        this.logger.warn('远程同步失败，使用本地配置', {
          error: syncResult.error,
        });
        this.configCache = localConfig;
      }

      this.lastSyncTime = new Date();

    } catch (error) {
      this.logger.error('配置初始化失败', {
        error: (error as Error).message,
      });

      // 创建默认配置
      this.createDefaultConfig();
      this.configCache = this.loadLocalConfig();
    }
  }

  /**
   * 加载本地配置文件
   */
  private loadLocalConfig(): any {
    try {
      if (fs.existsSync(this.CONFIG_FILE)) {
        const configContent = fs.readFileSync(this.CONFIG_FILE, 'utf8');
        const config = JSON.parse(configContent);
        this.logger.log('本地配置文件加载成功', {
          mapCount: config.maps?.length || 0,
          lastModified: config.lastModified,
        });
        return config;
      } else {
        this.logger.warn('本地配置文件不存在，将创建默认配置');
        return null;
      }
    } catch (error) {
      this.logger.error('加载本地配置文件失败', {
        error: (error as Error).message,
      });
      return null;
    }
  }

  /**
   * 创建默认配置文件
   */
  private createDefaultConfig(): void {
    const defaultConfig = {
      version: '2.0.0',
      lastModified: new Date().toISOString(),
      description: '统一配置管理 - 默认配置',
      source: 'default',
      maps: [
        {
          mapId: 'whale_port',
          mapName: '鲸之港',
          zulipStream: 'Whale Port',
          zulipStreamId: 5,
          description: '中心城区，交通枢纽与主要聚会点',
          isPublic: true,
          isWebPublic: false,
          interactionObjects: [
            {
              objectId: 'whale_port_general',
              objectName: 'General讨论区',
              zulipTopic: 'General',
              position: { x: 100, y: 100 },
              lastMessageId: 0
            }
          ]
        }
      ]
    };

    try {
      fs.writeFileSync(this.CONFIG_FILE, JSON.stringify(defaultConfig, null, 2), 'utf8');
      this.logger.log('默认配置文件创建成功');
    } catch (error) {
      this.logger.error('创建默认配置文件失败', {
        error: (error as Error).message,
      });
    }
  }

  /**
   * 从远程同步配置
   */
  private async syncFromRemote(): Promise<ConfigSyncResult> {
    const startTime = Date.now();

    try {
      // 检查是否可以连接远程
      if (!this.canConnectRemote()) {
        return {
          success: false,
          source: 'local',
          mapCount: 0,
          objectCount: 0,
          error: '缺少Zulip配置信息',
          lastUpdated: new Date()
        };
      }

      if (this.shouldUseLocalZulipConfig()) {
        return {
          success: false,
          source: 'local',
          mapCount: 0,
          objectCount: 0,
          error: '本地调试模式跳过Zulip远程同步',
          lastUpdated: new Date()
        };
      }

      // 测试连接
      const connected = await this.testZulipConnection();
      if (!connected) {
        return {
          success: false,
          source: 'local',
          mapCount: 0,
          objectCount: 0,
          error: '无法连接到Zulip服务器',
          lastUpdated: new Date()
        };
      }

      // 获取远程配置
      const remoteConfig = await this.fetchRemoteConfig();

      // 备份现有配置
      const backupCreated = this.backupCurrentConfig();

      // 更新配置文件
      this.saveConfigToFile(remoteConfig);

      const duration = Date.now() - startTime;
      this.logger.log(`远程配置同步完成，耗时 ${duration}ms`);

      return {
        success: true,
        source: 'remote',
        mapCount: remoteConfig.maps.length,
        objectCount: this.countObjects(remoteConfig),
        lastUpdated: new Date(),
        backupCreated
      };

    } catch (error) {
      this.logger.error('远程配置同步失败', {
        error: (error as Error).message,
        duration: Date.now() - startTime,
      });

      return {
        success: false,
        source: 'local',
        mapCount: 0,
        objectCount: 0,
        error: (error as Error).message,
        lastUpdated: new Date()
      };
    }
  }

  /**
   * 备份当前配置
   */
  private backupCurrentConfig(): boolean {
    try {
      if (!fs.existsSync(this.CONFIG_FILE)) {
        return false;
      }

      const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
      const backupFile = path.join(this.BACKUP_DIR, `map-config-backup-${timestamp}.json`);

      fs.copyFileSync(this.CONFIG_FILE, backupFile);

      this.logger.log('配置文件备份成功', { backupFile });

      // 清理旧备份（保留最近10个）
      this.cleanupOldBackups();

      return true;
    } catch (error) {
      this.logger.error('配置文件备份失败', {
        error: (error as Error).message,
      });
      return false;
    }
  }

  /**
   * 清理旧备份文件
   */
  private cleanupOldBackups(): void {
    try {
      const backupFiles = fs.readdirSync(this.BACKUP_DIR)
        .filter(file => file.startsWith('map-config-backup-'))
        .map(file => ({
          name: file,
          path: path.join(this.BACKUP_DIR, file),
          mtime: fs.statSync(path.join(this.BACKUP_DIR, file)).mtime
        }))
        .sort((a, b) => b.mtime.getTime() - a.mtime.getTime());

      // 保留最近10个备份
      const filesToDelete = backupFiles.slice(10);

      filesToDelete.forEach(file => {
        fs.unlinkSync(file.path);
        this.logger.log('删除旧备份文件', { file: file.name });
      });

    } catch (error) {
      this.logger.error('清理备份文件失败', {
        error: (error as Error).message,
      });
    }
  }

  /**
   * 保存配置到文件
   */
  private saveConfigToFile(config: any): void {
    try {
      fs.writeFileSync(this.CONFIG_FILE, JSON.stringify(config, null, 2), 'utf8');
      this.logger.log('配置文件保存成功');
    } catch (error) {
      this.logger.error('保存配置文件失败', {
        error: (error as Error).message,
      });
      throw error;
    }
  }

  /**
   * 启动定期同步
   */
  private startPeriodicSync(): void {
    if (this.syncTimer) {
      clearInterval(this.syncTimer);
    }

    this.syncTimer = setInterval(async () => {
      this.logger.log('开始定期配置同步');

      const syncResult = await this.syncFromRemote();

      if (syncResult.success) {
        this.configCache = this.loadLocalConfig();
        this.lastSyncTime = new Date();
        this.logger.log('定期配置同步成功');
      } else {
        this.logger.warn('定期配置同步失败，继续使用本地配置', {
          error: syncResult.error,
        });
      }
    }, this.SYNC_INTERVAL);

    this.logger.log('定期同步已启动', {
      intervalMinutes: this.SYNC_INTERVAL / 60000,
    });
  }

  /**
   * 检查是否可以连接远程
   */
  private canConnectRemote(): boolean {
    return !!(this.serverUrl && this.botEmail && this.apiKey);
  }

  /**
   * 本地调试时允许使用占位Zulip配置。
   */
  private shouldUseLocalZulipConfig(): boolean {
    const degradedModeEnabled = process.env.ZULIP_DEGRADED_MODE_ENABLED === 'true';
    const hasPlaceholderServer = this.serverUrl.includes('your-zulip-server.com');
    const hasPlaceholderApiKey = !this.apiKey || this.apiKey === 'your_bot_api_key';

    return degradedModeEnabled || hasPlaceholderServer || hasPlaceholderApiKey;
  }

  /**
   * 测试Zulip API连接
   */
  async testZulipConnection(): Promise<boolean> {
    if (!this.canConnectRemote() || this.shouldUseLocalZulipConfig()) {
      return false;
    }

    try {
      const response = await axios.get(`${this.serverUrl}/api/v1/users/me`, {
        headers: {
          'Authorization': this.authHeader,
          'Content-Type': 'application/json'
        },
        timeout: 10000
      });

      return response.status === 200;
    } catch (error) {
      this.logger.error('Zulip连接测试失败', {
        error: (error as Error).message,
      });
      return false;
    }
  }

  /**
   * 从Zulip服务器获取Stream列表
   */
  async getZulipStreams(): Promise<ZulipStream[]> {
    if (!this.canConnectRemote() || this.shouldUseLocalZulipConfig()) {
      throw new Error('缺少Zulip配置信息');
    }

    try {
      const response = await axios.get(`${this.serverUrl}/api/v1/streams`, {
        headers: {
          'Authorization': this.authHeader,
          'Content-Type': 'application/json'
        },
        params: {
          include_public: true,
          include_subscribed: true,
          include_all_active: true,
          include_default: true
        },
        timeout: 15000
      });

      if (response.status === 200) {
        return response.data.streams;
      }

      throw new Error(`API请求失败: ${response.status}`);
    } catch (error) {
      this.logger.error('获取Zulip Stream列表失败', {
        error: (error as Error).message,
      });
      throw error;
    }
  }

  /**
   * 获取指定Stream的Topic列表
   */
  async getZulipTopics(streamId: number): Promise<ZulipTopic[]> {
    if (!this.canConnectRemote()) {
      throw new Error('缺少Zulip配置信息');
    }

    try {
      const response = await axios.get(`${this.serverUrl}/api/v1/users/me/${streamId}/topics`, {
        headers: {
          'Authorization': this.authHeader,
          'Content-Type': 'application/json'
        },
        timeout: 10000
      });

      if (response.status === 200) {
        return response.data.topics;
      }

      return [];
    } catch (error) {
      this.logger.warn(`获取Stream ${streamId} 的Topic失败`, {
        error: (error as Error).message,
      });
      return [];
    }
  }

  /**
   * 从Zulip服务器获取完整配置
   */
  private async fetchRemoteConfig(): Promise<any> {
    this.logger.log('开始从Zulip服务器获取配置');

    const streams = await this.getZulipStreams();
    this.logger.log(`获取到 ${streams.length} 个Stream`);

    const mapConfig = {
      version: '2.0.0',
      lastModified: new Date().toISOString(),
      description: '统一配置管理 - 从Zulip服务器同步',
      source: 'remote',
      maps: [] as any[]
    };

    // 限制处理的Stream数量，避免请求过多
    const streamsToProcess = streams.slice(0, 15);
    let totalObjects = 0;

    for (const stream of streamsToProcess) {
      try {
        const topics = await this.getZulipTopics(stream.stream_id);

        // 生成地图ID
        const mapId = stream.name.toLowerCase()
          .replace(/\s+/g, '_')
          .replace(/[^a-z0-9_]/g, '')
          .substring(0, 50);

        const mapConfigItem = {
          mapId: mapId,
          mapName: stream.name,
          zulipStream: stream.name,
          zulipStreamId: stream.stream_id,
          description: stream.description || `${stream.name}频道`,
          isPublic: !stream.invite_only,
          isWebPublic: stream.is_web_public,
          interactionObjects: [] as any[]
        };

        // 为每个Topic创建交互对象
        topics.forEach((topic, topicIndex) => {
          // 跳过系统生成的Topic
          if (topic.name === 'channel events') {
            return;
          }

          const objectId = `${mapId}_${topic.name.toLowerCase().replace(/\s+/g, '_').replace(/[^a-z0-9_]/g, '')}`;

          mapConfigItem.interactionObjects.push({
            objectId: objectId,
            objectName: `${topic.name}讨论区`,
            zulipTopic: topic.name,
            position: {
              x: 100 + (topicIndex % 5) * 150,
              y: 100 + Math.floor(topicIndex / 5) * 100
            },
            lastMessageId: topic.max_id
          });

          totalObjects++;
        });

        mapConfig.maps.push(mapConfigItem);

        // 添加延迟避免请求过于频繁
        await new Promise(resolve => setTimeout(resolve, 200));

      } catch (error) {
        this.logger.warn(`处理Stream ${stream.name} 失败`, {
          error: (error as Error).message,
        });
      }
    }

    this.logger.log('远程配置获取完成', {
      mapCount: mapConfig.maps.length,
      totalObjects,
    });

    return mapConfig;
  }

  /**
   * 获取当前配置
   */
  async getConfig(): Promise<any> {
    // 如果缓存存在，直接返回
    if (this.configCache) {
      return this.configCache;
    }

    // 否则加载本地配置
    const localConfig = this.loadLocalConfig();
    if (localConfig) {
      this.configCache = localConfig;
      return localConfig;
    }

    // 如果本地配置也不存在，创建默认配置
    this.createDefaultConfig();
    this.configCache = this.loadLocalConfig();
    return this.configCache;
  }

  /**
   * 手动触发配置同步
   */
  async syncConfig(): Promise<ConfigSyncResult> {
    this.logger.log('手动触发配置同步');

    const syncResult = await this.syncFromRemote();

    if (syncResult.success) {
      this.configCache = this.loadLocalConfig();
      this.lastSyncTime = new Date();
    }

    return syncResult;
  }

  /**
   * 计算配置中的对象总数
   */
  private countObjects(config: any): number {
    if (!config.maps || !Array.isArray(config.maps)) {
      return 0;
    }

    return config.maps.reduce((total: number, map: any) => {
      return total + (map.interactionObjects?.length || 0);
    }, 0);
  }

  /**
   * 获取配置状态信息
   */
  getConfigStatus(): any {
    const config = this.configCache || this.loadLocalConfig();

    return {
      hasRemoteCredentials: this.canConnectRemote(),
      lastSyncTime: this.lastSyncTime,
      hasLocalConfig: !!config,
      configSource: config?.source || 'unknown',
      configVersion: config?.version || 'unknown',
      mapCount: config?.maps?.length || 0,
      objectCount: this.countObjects(config || {}),
      syncIntervalMinutes: this.SYNC_INTERVAL / 60000,
      configFile: this.CONFIG_FILE,
      backupDir: this.BACKUP_DIR,
    };
  }

  /**
   * 根据地图ID获取Stream名称（兼容原接口）
   */
  async getStreamByMap(mapId: string): Promise<string | null> {
    try {
      const config = await this.getConfig();
      const map = config.maps?.find((m: any) => m.mapId === mapId);
      return map?.zulipStream || null;
    } catch (error) {
      this.logger.error('获取Stream失败', {
        mapId,
        error: (error as Error).message,
      });
      return null;
    }
  }

  /**
   * 根据Stream名称获取地图ID（兼容原接口）
   */
  async getMapIdByStream(streamName: string): Promise<string | null> {
    try {
      const config = await this.getConfig();
      const map = config.maps?.find((m: any) => m.zulipStream === streamName);
      return map?.mapId || null;
    } catch (error) {
      this.logger.error('获取地图ID失败', {
        streamName,
        error: (error as Error).message,
      });
      return null;
    }
  }

  /**
   * 获取所有地图配置（兼容原接口）
   */
  async getAllMapConfigs(): Promise<any[]> {
    try {
      const config = await this.getConfig();
      return config.maps || [];
    } catch (error) {
      this.logger.error('获取所有地图配置失败', {
        error: (error as Error).message,
      });
      return [];
    }
  }

  /**
   * 获取备份文件列表
   */
  getBackupFiles(): any[] {
    try {
      if (!fs.existsSync(this.BACKUP_DIR)) {
        return [];
      }

      return fs.readdirSync(this.BACKUP_DIR)
        .filter(file => file.startsWith('map-config-backup-'))
        .map(file => {
          const filePath = path.join(this.BACKUP_DIR, file);
          const stats = fs.statSync(filePath);
          return {
            name: file,
            path: filePath,
            size: stats.size,
            created: stats.mtime,
          };
        })
        .sort((a, b) => b.created.getTime() - a.created.getTime());

    } catch (error) {
      this.logger.error('获取备份文件列表失败', {
        error: (error as Error).message,
      });
      return [];
    }
  }

  /**
   * 从备份恢复配置
   */
  async restoreFromBackup(backupFileName: string): Promise<boolean> {
    try {
      const backupFile = path.join(this.BACKUP_DIR, backupFileName);

      if (!fs.existsSync(backupFile)) {
        throw new Error('备份文件不存在');
      }

      // 备份当前配置
      this.backupCurrentConfig();

      // 恢复备份
      fs.copyFileSync(backupFile, this.CONFIG_FILE);

      // 重新加载配置
      this.configCache = this.loadLocalConfig();

      this.logger.log('配置恢复成功', { backupFile: backupFileName });
      return true;

    } catch (error) {
      this.logger.error('配置恢复失败', {
        backupFile: backupFileName,
        error: (error as Error).message,
      });
      return false;
    }
  }

  /**
   * 清理资源
   */
  onModuleDestroy(): void {
    if (this.syncTimer) {
      clearInterval(this.syncTimer);
      this.syncTimer = null;
    }
  }
}
