import { Injectable, Logger, NotFoundException, BadRequestException, HttpStatus } from '@nestjs/common';
import { BusinessException } from '@common/exceptions/business.exception';
import { PrismaService } from '@core/database/prisma/prisma.service';
import {
  CreateDefinitionDto,
  UpdateDefinitionDto,
  CreateVersionDto,
  UpdateVersionDto,
  DeployVersionDto,
  DefinitionsQueryDto,
} from './dto/approval.dto';
import {
  ProcessDefinitionItem,
  ProcessVersionItem,
  ProcessVersionDetailResponse,
} from './dto/approval-response.dto';

@Injectable()
export class DefinitionService {
  private readonly logger = new Logger(DefinitionService.name);

  constructor(private readonly prisma: PrismaService) {}

  // ==================== Controller 调用的方法别名 ====================

  async findAll(query: DefinitionsQueryDto) {
    const result = await this.listDefinitions({
      category: query.category,
      status: query.status,
      page: query.page,
      limit: query.limit,
    });

    return {
      items: result.items,
      total: result.total,
      page: query.page || 1,
      limit: query.limit || 20,
      totalPages: Math.ceil(result.total / (query.limit || 20)),
      hasNext: (query.page || 1) * (query.limit || 20) < result.total,
      hasPrev: (query.page || 1) > 1,
    };
  }

  async create(dto: CreateDefinitionDto, userId: string) {
    return this.createDefinition(dto, userId);
  }

  async findByKey(key: string) {
    return this.getDefinition(key);
  }

  async update(key: string, dto: UpdateDefinitionDto, userId: string) {
    return this.updateDefinition(key, dto, userId);
  }

  async delete(key: string) {
    return this.deleteDefinition(key);
  }

  async getVersions(key: string) {
    const versions = await this.listVersions(key);
    return { items: versions };
  }

  async syncFromConfig(userId: string) {
    this.logger.log(`Syncing process definitions from config by user ${userId}`);
    // 这里可以从配置文件或外部源同步流程定义
    // 暂时返回一个简单的响应
    return {
      success: true,
      message: '流程配置同步成功',
      syncedCount: 0,
    };
  }

  // ==================== 流程定义管理 ====================

  async listDefinitions(params: {
    category?: string;
    status?: string;
    page?: number;
    limit?: number;
  }): Promise<{ items: ProcessDefinitionItem[]; total: number }> {
    const where: any = {};

    if (params.category) {
      where.category = params.category;
    }

    if (params.status) {
      where.status = params.status;
    }

    const [definitions, total] = await Promise.all([
      this.prisma.approvalDefinition.findMany({
        where,
        orderBy: { createdAt: 'desc' },
        skip: ((params.page || 1) - 1) * (params.limit || 20),
        take: params.limit || 20,
      }),
      this.prisma.approvalDefinition.count({ where }),
    ]);

    const items: ProcessDefinitionItem[] = definitions.map((def) => ({
      id: def.id,
      key: def.key,
      name: def.name,
      category: def.category,
      description: def.description || undefined,
      latestVersion: def.latestVersion,
      status: def.status as any,
      organizationId: def.organizationId || undefined,
      createdAt: def.createdAt.toISOString(),
      updatedAt: def.updatedAt.toISOString(),
    }));

    return { items, total };
  }

  async getDefinition(key: string): Promise<ProcessDefinitionItem> {
    const definition = await this.prisma.approvalDefinition.findUnique({
      where: { key },
    });

    if (!definition) {
      throw new NotFoundException(`流程定义不存在: ${key}`);
    }

    return {
      id: definition.id,
      key: definition.key,
      name: definition.name,
      category: definition.category,
      description: definition.description || undefined,
      latestVersion: definition.latestVersion,
      status: definition.status as any,
      organizationId: definition.organizationId || undefined,
      createdAt: definition.createdAt.toISOString(),
      updatedAt: definition.updatedAt.toISOString(),
    };
  }

  async createDefinition(dto: CreateDefinitionDto, createdBy: string): Promise<ProcessDefinitionItem> {
    // 检查 key 是否已存在
    const existing = await this.prisma.approvalDefinition.findUnique({
      where: { key: dto.key },
    });

    if (existing) {
      throw new BusinessException(
        `流程定义 key 已存在: ${dto.key}`,
        'DEFINITION_KEY_EXISTS',
        HttpStatus.CONFLICT,
      );
    }

    const definition = await this.prisma.approvalDefinition.create({
      data: {
        key: dto.key,
        name: dto.name,
        category: dto.category || 'DEFAULT',
        description: dto.description,
        organizationId: dto.organizationId,
        status: 'ACTIVE',
        createdBy,
      },
    });

    return {
      id: definition.id,
      key: definition.key,
      name: definition.name,
      category: definition.category,
      description: definition.description || undefined,
      latestVersion: definition.latestVersion,
      status: definition.status as any,
      organizationId: definition.organizationId || undefined,
      createdAt: definition.createdAt.toISOString(),
      updatedAt: definition.updatedAt.toISOString(),
    };
  }

  async updateDefinition(key: string, dto: UpdateDefinitionDto, updatedBy: string): Promise<ProcessDefinitionItem> {
    const definition = await this.prisma.approvalDefinition.findUnique({
      where: { key },
    });

    if (!definition) {
      throw new NotFoundException(`流程定义不存在: ${key}`);
    }

    const updated = await this.prisma.approvalDefinition.update({
      where: { key },
      data: {
        name: dto.name,
        description: dto.description,
        status: dto.status as any,
        updatedBy,
      },
    });

    return {
      id: updated.id,
      key: updated.key,
      name: updated.name,
      category: updated.category,
      description: updated.description || undefined,
      latestVersion: updated.latestVersion,
      status: updated.status as any,
      organizationId: updated.organizationId || undefined,
      createdAt: updated.createdAt.toISOString(),
      updatedAt: updated.updatedAt.toISOString(),
    };
  }

  async deleteDefinition(key: string): Promise<{ success: boolean; message: string }> {
    const definition = await this.prisma.approvalDefinition.findUnique({
      where: { key },
      include: {
        versions: {
          include: {
            instances: {
              where: {
                status: 'RUNNING',
              },
              take: 1,
            },
          },
        },
      },
    });

    if (!definition) {
      throw new NotFoundException(`流程定义不存在: ${key}`);
    }

    // 检查是否有运行中的实例
    const hasRunningInstances = definition.versions.some(
      (v) => v.instances.length > 0,
    );

    if (hasRunningInstances) {
      throw new BadRequestException('有运行中的流程实例，无法删除流程定义');
    }

    // 删除流程定义（级联删除版本）
    await this.prisma.approvalDefinition.delete({
      where: { key },
    });

    return {
      success: true,
      message: `流程定义 ${key} 已删除`,
    };
  }

  // ==================== 流程版本管理 ====================

  async listVersions(key: string): Promise<ProcessVersionItem[]> {
    const definition = await this.prisma.approvalDefinition.findUnique({
      where: { key },
    });

    if (!definition) {
      throw new NotFoundException(`流程定义不存在: ${key}`);
    }

    const versions = await this.prisma.approvalVersion.findMany({
      where: { definitionId: definition.id },
      orderBy: { version: 'desc' },
    });

    return versions.map((v) => ({
      id: v.id,
      version: v.version,
      name: v.name,
      status: v.status as any,
      isDefault: v.isDefault,
      deployedAt: v.deployedAt?.toISOString(),
      changeLog: v.changeLog || undefined,
      createdAt: v.createdAt.toISOString(),
    }));
  }

  async getVersion(key: string, version: number): Promise<ProcessVersionDetailResponse> {
    const definition = await this.prisma.approvalDefinition.findUnique({
      where: { key },
    });

    if (!definition) {
      throw new NotFoundException(`流程定义不存在: ${key}`);
    }

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

    if (!versionRecord) {
      throw new NotFoundException(`版本不存在: ${version}`);
    }

    return {
      id: versionRecord.id,
      version: versionRecord.version,
      name: versionRecord.name,
      status: versionRecord.status as any,
      isDefault: versionRecord.isDefault,
      deployedAt: versionRecord.deployedAt?.toISOString(),
      changeLog: versionRecord.changeLog || undefined,
      createdAt: versionRecord.createdAt.toISOString(),
      processModel: versionRecord.processModel as any,
      settings: versionRecord.settings as any,
    };
  }

  async createVersion(key: string, dto: CreateVersionDto, createdBy: string): Promise<ProcessVersionItem> {
    const definition = await this.prisma.approvalDefinition.findUnique({
      where: { key },
    });

    if (!definition) {
      throw new NotFoundException(`流程定义不存在: ${key}`);
    }

    // 获取下一个版本号
    const latestVersion = await this.prisma.approvalVersion.findFirst({
      where: { definitionId: definition.id },
      orderBy: { version: 'desc' },
    });

    const nextVersion = (latestVersion?.version || 0) + 1;

    // 验证流程模型
    this.validateProcessModel(dto.processModel);

    const version = await this.prisma.approvalVersion.create({
      data: {
        definitionId: definition.id,
        version: nextVersion,
        name: dto.name,
        processModel: dto.processModel,
        settings: dto.settings || {},
        changeLog: dto.changeLog,
        status: 'DRAFT',
      },
    });

    return {
      id: version.id,
      version: version.version,
      name: version.name,
      status: version.status as any,
      isDefault: version.isDefault,
      changeLog: version.changeLog || undefined,
      createdAt: version.createdAt.toISOString(),
    };
  }

  async updateVersion(
    key: string,
    version: number,
    dto: UpdateVersionDto,
    updatedBy: string,
  ): Promise<ProcessVersionItem> {
    const definition = await this.prisma.approvalDefinition.findUnique({
      where: { key },
    });

    if (!definition) {
      throw new NotFoundException(`流程定义不存在: ${key}`);
    }

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

    if (!versionRecord) {
      throw new NotFoundException(`版本不存在: ${version}`);
    }

    if (versionRecord.status !== 'DRAFT') {
      throw new BadRequestException('只能修改草稿状态的版本');
    }

    // 验证流程模型
    if (dto.processModel) {
      this.validateProcessModel(dto.processModel);
    }

    const updated = await this.prisma.approvalVersion.update({
      where: { id: versionRecord.id },
      data: {
        name: dto.name,
        processModel: dto.processModel,
        settings: dto.settings,
        changeLog: dto.changeLog,
      },
    });

    return {
      id: updated.id,
      version: updated.version,
      name: updated.name,
      status: updated.status as any,
      isDefault: updated.isDefault,
      changeLog: updated.changeLog || undefined,
      createdAt: updated.createdAt.toISOString(),
    };
  }

  async deployVersion(
    key: string,
    version: number,
    dto: DeployVersionDto,
    deployedBy: string,
  ): Promise<ProcessVersionItem> {
    const definition = await this.prisma.approvalDefinition.findUnique({
      where: { key },
    });

    if (!definition) {
      throw new NotFoundException(`流程定义不存在: ${key}`);
    }

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

    if (!versionRecord) {
      throw new NotFoundException(`版本不存在: ${version}`);
    }

    if (versionRecord.status !== 'DRAFT') {
      throw new BadRequestException('只能部署草稿状态的版本');
    }

    // 开始事务
    const result = await this.prisma.$transaction(async (tx) => {
      // 如果设置为默认版本，取消其他版本的默认状态
      if (dto.setAsDefault !== false) {
        await tx.approvalVersion.updateMany({
          where: {
            definitionId: definition.id,
            isDefault: true,
          },
          data: { isDefault: false },
        });
      }

      // 更新版本状态
      const deployed = await tx.approvalVersion.update({
        where: { id: versionRecord.id },
        data: {
          status: 'DEPLOYED',
          isDefault: dto.setAsDefault !== false,
          deployedAt: new Date(),
          deployedBy,
        },
      });

      // 更新定义的最新版本
      await tx.approvalDefinition.update({
        where: { id: definition.id },
        data: { latestVersion: version },
      });

      return deployed;
    });

    return {
      id: result.id,
      version: result.version,
      name: result.name,
      status: result.status as any,
      isDefault: result.isDefault,
      deployedAt: result.deployedAt?.toISOString(),
      changeLog: result.changeLog || undefined,
      createdAt: result.createdAt.toISOString(),
    };
  }

  // ==================== 辅助方法 ====================

  private validateProcessModel(processModel: any): void {
    if (!processModel.nodes || !Array.isArray(processModel.nodes)) {
      throw new BadRequestException('流程模型必须包含 nodes 数组');
    }

    if (!processModel.edges || !Array.isArray(processModel.edges)) {
      throw new BadRequestException('流程模型必须包含 edges 数组');
    }

    // 检查必须有开始节点
    const startNodes = processModel.nodes.filter((n: any) => n.type === 'START');
    if (startNodes.length === 0) {
      throw new BadRequestException('流程模型必须包含 START 节点');
    }

    if (startNodes.length > 1) {
      throw new BadRequestException('流程模型只能有一个 START 节点');
    }

    // 检查必须有结束节点
    const endNodes = processModel.nodes.filter((n: any) => n.type === 'END');
    if (endNodes.length === 0) {
      throw new BadRequestException('流程模型必须包含 END 节点');
    }

    // 检查所有节点都有 id 和 type
    for (const node of processModel.nodes) {
      if (!node.id) {
        throw new BadRequestException('所有节点必须有 id');
      }
      if (!node.type) {
        throw new BadRequestException('所有节点必须有 type');
      }
    }

    // 检查边的连接是否有效
    const nodeIds = new Set(processModel.nodes.map((n: any) => n.id));
    for (const edge of processModel.edges) {
      if (!nodeIds.has(edge.source)) {
        throw new BadRequestException(`边的 source 节点不存在: ${edge.source}`);
      }
      if (!nodeIds.has(edge.target)) {
        throw new BadRequestException(`边的 target 节点不存在: ${edge.target}`);
      }
    }
  }
}

