import { Injectable, Logger, OnModuleInit } from '@nestjs/common';
import { PrismaService } from '@core/database/prisma/prisma.service';
import { ConfigService } from '@nestjs/config';
import * as fs from 'fs';
import * as path from 'path';
import * as yaml from 'js-yaml';

interface ProcessConfig {
  meta: {
    key: string;
    name: string;
    description: string;
    category: string;
    version: number;
    author?: string;
    createdAt?: string;
    changelog?: Array<{
      version: number;
      date: string;
      changes: string[];
    }>;
  };
  process: {
    nodes: any[];
    edges: any[];
    variables: any[];
  };
  deployment: {
    autoApply: {
      development: boolean;
      staging: boolean;
      production: boolean;
    };
    rollback: {
      enabled: boolean;
      keepVersions: number;
    };
  };
}

@Injectable()
export class ProcessLoaderService implements OnModuleInit {
  private readonly logger = new Logger(ProcessLoaderService.name);
  private readonly configDir: string;

  constructor(
    private prisma: PrismaService,
    private configService: ConfigService,
  ) {
    this.configDir = path.join(process.cwd(), 'config', 'processes');
  }

  /**
   * 应用启动时自动加载流程
   */
  async onModuleInit() {
    const autoSync =
      this.configService.get('PROCESS_AUTO_SYNC', 'true') === 'true';

    if (autoSync) {
      this.logger.log('🔄 Auto-syncing processes from config files...');
      try {
        await this.syncAllProcesses();
      } catch (error) {
        this.logger.error('Failed to auto-sync processes:', error);
        // 不抛出异常，允许应用继续启动
      }
    }
  }

  /**
   * 同步所有流程配置
   */
  async syncAllProcesses() {
    try {
      // 检查配置目录是否存在
      if (!fs.existsSync(this.configDir)) {
        this.logger.warn(
          `Config directory not found: ${this.configDir}`,
        );
        return {
          created: 0,
          updated: 0,
          skipped: 0,
          errors: 0,
        };
      }

      const files = fs.readdirSync(this.configDir);
      const yamlFiles = files.filter(
        (f) => f.endsWith('.yml') || f.endsWith('.yaml'),
      );

      this.logger.log(
        `📂 Found ${yamlFiles.length} process config file(s)`,
      );

      const results = {
        created: 0,
        updated: 0,
        skipped: 0,
        errors: 0,
      };

      for (const file of yamlFiles) {
        try {
          const result = await this.syncProcess(file);
          results[result]++;
        } catch (error) {
          this.logger.error(`❌ Failed to sync ${file}:`, error);
          results.errors++;
        }
      }

      this.logger.log('✅ Process sync complete:');
      this.logger.log(`  Created: ${results.created}`);
      this.logger.log(`  Updated: ${results.updated}`);
      this.logger.log(`  Skipped: ${results.skipped}`);
      if (results.errors > 0) {
        this.logger.log(`  Errors: ${results.errors}`);
      }

      return results;
    } catch (error) {
      this.logger.error('Failed to sync processes:', error);
      throw error;
    }
  }

  /**
   * 同步单个流程
   */
  async syncProcess(
    filename: string,
  ): Promise<'created' | 'updated' | 'skipped'> {
    const filePath = path.join(this.configDir, filename);
    this.logger.log(`📄 Processing: ${filename}`);

    // 1. 读取配置文件
    const fileContent = fs.readFileSync(filePath, 'utf8');
    const config = yaml.load(fileContent) as ProcessConfig;

    // 2. 验证配置
    this.validateConfig(config);

    const { meta, process: processModel, deployment } = config;

    // 3. 检查是否允许自动应用
    const env = this.configService.get('NODE_ENV', 'development') as 'development' | 'staging' | 'production';
    const canAutoApply = deployment.autoApply[env] ?? true;

    if (!canAutoApply) {
      this.logger.warn(
        `⚠️  Auto-apply disabled for ${env} environment: ${meta.key}`,
      );
      return 'skipped';
    }

    // 4. 查找或创建流程定义
    let definition = await this.prisma.approvalDefinition.findUnique({
      where: { key: meta.key },
      include: {
        versions: {
          orderBy: { version: 'desc' },
          take: 1,
        },
      },
    });

    if (!definition) {
      // 创建新流程定义
      definition = await this.prisma.approvalDefinition.create({
        data: {
          key: meta.key,
          name: meta.name,
          description: meta.description,
          category: meta.category,
          latestVersion: meta.version,
          createdBy: meta.author || 'system',
        },
        include: { versions: true },
      });
      this.logger.log(
        `✨ Created new process definition: ${meta.key}`,
      );
    } else {
      // 更新流程定义的基本信息
      await this.prisma.approvalDefinition.update({
        where: { id: definition.id },
        data: {
          name: meta.name,
          description: meta.description,
          category: meta.category,
        },
      });
    }

    // 5. 检查版本号
    const latestVersion = definition.versions[0]?.version || 0;
    const newVersion = meta.version;

    if (newVersion < latestVersion) {
      this.logger.log(
        `⏭️  Skipped ${meta.key}: version ${newVersion} < current version ${latestVersion}`,
      );
      return 'skipped';
    }

    if (newVersion === latestVersion) {
      // 版本号相同，更新现有版本的内容并设为默认
      const existingVersion = await this.prisma.approvalVersion.findFirst({
        where: {
          definitionId: definition.id,
          version: newVersion,
        },
      });

      if (existingVersion) {
        // 取消所有版本的默认标记
        await this.prisma.approvalVersion.updateMany({
          where: { definitionId: definition.id },
          data: { isDefault: false },
        });

        // 更新现有版本并设为默认
        await this.prisma.approvalVersion.update({
          where: { id: existingVersion.id },
          data: {
            name: `${meta.name} v${newVersion}`,
            processModel: processModel as any,
            isDefault: true,
            status: 'DEPLOYED', // 设置为已部署状态
            deployedAt: new Date(),
            deployedBy: meta.author || 'system',
            changeLog: this.generateChangeLog(config),
          },
        });

        // 更新流程定义的最新版本号（确保同步）
        await this.prisma.approvalDefinition.update({
          where: { id: definition.id },
          data: { latestVersion: newVersion },
        });

        this.logger.log(
          `🔄 Updated ${meta.key} v${newVersion} and set as default`,
        );
        return 'updated';
      }
    }

    // 6. 创建新版本
    await this.prisma.approvalVersion.create({
      data: {
        definitionId: definition.id,
        name: `${meta.name} v${newVersion}`,
        version: newVersion,
        processModel: processModel as any,
        isDefault: true, // 新版本设为默认
        status: 'DEPLOYED', // 设置为已部署状态
        deployedAt: new Date(),
        deployedBy: meta.author || 'system',
        changeLog: this.generateChangeLog(config),
      },
    });

    // 7. 更新流程定义的最新版本号
    await this.prisma.approvalDefinition.update({
      where: { id: definition.id },
      data: { latestVersion: newVersion },
    });

    // 8. 取消旧版本的默认标记
    if (latestVersion > 0) {
      await this.prisma.approvalVersion.updateMany({
        where: {
          definitionId: definition.id,
          version: { lt: newVersion },
        },
        data: {
          isDefault: false,
        },
      });
    }

    // 9. 清理旧版本（保留指定数量）
    if (deployment.rollback.enabled) {
      await this.cleanupOldVersions(
        definition.id,
        deployment.rollback.keepVersions,
      );
    }

    this.logger.log(
      `✅ Applied ${meta.key} v${newVersion} (previous: v${latestVersion})`,
    );

    return latestVersion === 0 ? 'created' : 'updated';
  }

  /**
   * 验证配置文件
   */
  private validateConfig(config: ProcessConfig) {
    const { meta, process } = config;

    if (!meta.key) {
      throw new Error('Process key is required');
    }
    if (!meta.name) {
      throw new Error('Process name is required');
    }
    if (!meta.version || meta.version < 1) {
      throw new Error('Valid version number (>=1) is required');
    }
    if (!process.nodes || process.nodes.length === 0) {
      throw new Error('Process must have at least one node');
    }

    // 验证必须有 START 和 END 节点
    const hasStart = process.nodes.some((n) => n.type === 'START');
    const hasEnd = process.nodes.some((n) => n.type === 'END');

    if (!hasStart) {
      throw new Error('Process must have a START node');
    }
    if (!hasEnd) {
      throw new Error('Process must have an END node');
    }

    // 验证节点类型
    const validTypes = ['START', 'END', 'USER_TASK', 'SERVICE_TASK', 'GATEWAY'];
    for (const node of process.nodes) {
      if (!validTypes.includes(node.type)) {
        throw new Error(
          `Invalid node type: ${node.type}. Must be one of: ${validTypes.join(', ')}`,
        );
      }
    }
  }

  /**
   * 清理旧版本
   */
  private async cleanupOldVersions(
    definitionId: string,
    keepVersions: number,
  ) {
    const versions = await this.prisma.approvalVersion.findMany({
      where: { definitionId },
      orderBy: { version: 'desc' },
      select: { id: true, version: true },
    });

    if (versions.length > keepVersions) {
      const toDelete = versions.slice(keepVersions);
      
      // 检查是否有正在运行的流程实例使用这些版本
      for (const version of toDelete) {
        const runningInstances = await this.prisma.approvalInstance.count({
          where: {
            versionId: version.id,
            status: 'RUNNING',
          },
        });

        if (runningInstances > 0) {
          this.logger.warn(
            `⚠️  Cannot delete version ${version.version}: ${runningInstances} running instance(s)`,
          );
          continue;
        }

        await this.prisma.approvalVersion.delete({
          where: { id: version.id },
        });
      }

      this.logger.log(
        `🗑️  Cleaned up ${toDelete.length} old version(s)`,
      );
    }
  }

  /**
   * 手动触发同步（用于生产环境）
   */
  async manualSync(processKey?: string) {
    if (processKey) {
      const filename = `${processKey
        .toLowerCase()
        .replace(/_/g, '-')}.yml`;
      return this.syncProcess(filename);
    } else {
      return this.syncAllProcesses();
    }
  }

  /**
   * 回滚到指定版本
   */
  async rollback(processKey: string, version: number) {
    const definition =
      await this.prisma.approvalDefinition.findUnique({
        where: { key: processKey },
      });

    if (!definition) {
      throw new Error(`Process ${processKey} not found`);
    }

    const targetVersion =
      await this.prisma.approvalVersion.findUnique({
        where: {
          definitionId_version: {
            definitionId: definition.id,
            version,
          },
        },
      });

    if (!targetVersion) {
      throw new Error(`Version ${version} not found for ${processKey}`);
    }

    // 取消所有版本的默认标记
    await this.prisma.approvalVersion.updateMany({
      where: { definitionId: definition.id },
      data: { isDefault: false },
    });

    // 设置目标版本为默认
    await this.prisma.approvalVersion.update({
      where: { id: targetVersion.id },
      data: { isDefault: true },
    });

    this.logger.log(
      `↩️  Rolled back ${processKey} to v${version}`,
    );

    return targetVersion;
  }

  /**
   * 获取流程列表
   */
  async listProcesses() {
    return this.prisma.approvalDefinition.findMany({
      include: {
        versions: {
          where: { isDefault: true },
          take: 1,
        },
      },
    });
  }

  /**
   * 获取流程版本历史
   */
  async getVersionHistory(processKey: string) {
    const definition =
      await this.prisma.approvalDefinition.findUnique({
        where: { key: processKey },
        include: {
          versions: {
            orderBy: { version: 'desc' },
          },
        },
      });

    if (!definition) {
      throw new Error(`Process ${processKey} not found`);
    }

    return definition.versions;
  }

  /**
   * 生成变更日志
   */
  private generateChangeLog(config: ProcessConfig): string {
    const { meta } = config;
    
    // 如果配置中有 changelog，使用它
    if (meta.changelog && meta.changelog.length > 0) {
      const latestChange = meta.changelog.find(c => c.version === meta.version);
      if (latestChange) {
        return `[v${latestChange.version}] ${latestChange.date}\n${latestChange.changes.map(c => `- ${c}`).join('\n')}`;
      }
    }
    
    // 否则生成默认变更日志
    const timestamp = meta.createdAt || new Date().toISOString().split('T')[0];
    return `[v${meta.version}] ${timestamp}\n- 流程配置更新\n- 由 ${meta.author || 'system'} 部署`;
  }
}

