import {
  Injectable,
  Logger,
  NotFoundException,
  BadRequestException,
  ForbiddenException,
  Inject,
  forwardRef,
} from '@nestjs/common';
import { PrismaService } from '@core/database/prisma/prisma.service';
import { FormInstance, FormDefinition, FormInstanceStatus } from '@prisma/client';
import { ApprovalCompletedCallbackDto } from '../dto/form-approval-callback.dto';
import { ApprovalService } from '@engines/approval/approval.service';
import { SkipAssertAccess } from '@common/decorators/skip-assert-access.decorator';

/**
 * 表单引擎与审批流引擎集成服务
 */
@Injectable()
export class FormApprovalIntegrationService {
  private readonly logger = new Logger(FormApprovalIntegrationService.name);

  constructor(
    private prisma: PrismaService,
    @Inject(forwardRef(() => ApprovalService))
    private approvalService: ApprovalService,
  ) {}

  /**
   * 提交表单并启动审批流（由 FormInstanceService 调用）
   * 
   * @param instance 表单实例
   * @param form 表单定义
   * @param userId 提交人ID
   * @param comment 提交意见（可选）
   * @returns 审批启动结果
   */
  async submitWithApproval(
    instance: FormInstance,
    form: FormDefinition,
    userId: string,
    comment?: string,
  ) {
    this.logger.log(
      `Checking if form ${form.key} requires approval for instance ${instance.id}`,
    );

    // 1. 检查是否需要审批
    if (!form.requiresApproval || !form.approvalProcessKey) {
      this.logger.log(`Form ${form.key} does not require approval`);
      return { needsApproval: false, approvalInstance: null };
    }

    this.logger.log(
      `Form requires approval with process: ${form.approvalProcessKey}`,
    );

    // 2. 启动审批流
    try {
      const approvalResult = await this.approvalService.startApproval({
        processDefinitionKey: form.approvalProcessKey,
        businessType: 'FORM_INSTANCE',
        businessId: instance.id,
        variables: {
          formKey: form.key,
          formName: form.name,
          formData: instance.data,
          submitterId: userId,
          submitComment: comment,
          ...(instance.data as Record<string, any>), // 合并表单数据用于条件判断
        },
        title: `表单审批：${form.name}`,
        priority: 1,
      }, userId);

      this.logger.log(
        `Approval instance created: ${approvalResult.instanceId}`,
      );

      // 4. 更新表单实例
      await this.prisma.formInstance.update({
        where: { id: instance.id },
        data: {
          status: FormInstanceStatus.PENDING_APPROVAL,
          approvalInstanceId: approvalResult.instanceId,
          approvalStatus: 'RUNNING',
          approvalStartTime: new Date(),
        },
      });

      this.logger.log(
        `FormInstance ${instance.id} status updated to PENDING_APPROVAL`,
      );

      return {
        needsApproval: true,
        approvalInstance: {
          id: approvalResult.instanceId,
          workflowId: approvalResult.workflowId,
          status: approvalResult.status,
        },
      };
    } catch (error) {
      this.logger.error(
        `Failed to start approval for form instance ${instance.id}:`,
        error.stack,
      );
      throw new BadRequestException(
        `Failed to start approval process: ${error.message}`,
      );
    }
  }

  /**
   * 处理审批完成回调（由审批流引擎调用）
   * 
   * @param dto 回调数据
   * @returns 更新后的表单实例
   */
  @SkipAssertAccess('审批引擎 → 表单引擎的系统内部回调，无用户上下文；权限校验已发生在审批引擎触发审批动作时，回调只做状态机映射不引入新写入决策')
  async handleApprovalCompleted(dto: ApprovalCompletedCallbackDto) {
    this.logger.log(
      `Handling approval completed callback for approval ${dto.approvalInstanceId}, businessId: ${dto.businessId}`,
    );

    const { approvalInstanceId, businessId, status, endReason, endTime } = dto;

    // 1. 查找表单实例
    const instance = await this.prisma.formInstance.findUnique({
      where: { id: businessId },
    });

    if (!instance) {
      this.logger.error(`FormInstance ${businessId} not found`);
      throw new NotFoundException(`FormInstance ${businessId} not found`);
    }

    // 2. 映射状态
    let newStatus: FormInstanceStatus;
    if (status === 'COMPLETED') {
      newStatus = FormInstanceStatus.APPROVED;
    } else if (status === 'TERMINATED') {
      if (endReason === 'REJECTED') {
        newStatus = FormInstanceStatus.REJECTED;
      } else if (endReason === 'WITHDRAWN') {
        newStatus = FormInstanceStatus.WITHDRAWN;
      } else {
        // ERROR 或其他原因，视为驳回
        newStatus = FormInstanceStatus.REJECTED;
      }
    } else {
      // 不应该到这里，保持原状态
      this.logger.warn(
        `Unexpected approval status: ${status}, keeping current form status`,
      );
      return instance;
    }

    this.logger.log(
      `Mapping approval status ${status} (${endReason}) to form status ${newStatus}`,
    );

    // 3. 更新表单实例
    const updated = await this.prisma.formInstance.update({
      where: { id: businessId },
      data: {
        status: newStatus,
        approvalStatus: status,
        approvalEndTime: endTime ? new Date(endTime) : new Date(),
        updatedAt: new Date(),
      },
    });

    this.logger.log(
      `FormInstance ${businessId} updated to ${newStatus} after approval ${status}`,
    );

    return updated;
  }

  /**
   * 查询审批状态（用于前端显示）
   * 
   * @param instanceId 表单实例ID
   * @returns 审批状态详情
   */
  async getApprovalStatus(instanceId: string) {
    this.logger.log(`Fetching approval status for form instance ${instanceId}`);

    // 1. 查找表单实例
    const instance = await this.prisma.formInstance.findUnique({
      where: { id: instanceId },
      include: {
        definition: {
          select: {
            key: true,
            name: true,
          },
        },
        creator: { select: { id: true, displayName: true } },
        submitter: { select: { id: true, displayName: true } },
      },
    });

    if (!instance) {
      throw new NotFoundException(`FormInstance ${instanceId} not found`);
    }

    // 2. 如果没有关联审批实例，返回基本信息
    if (!instance.approvalInstanceId) {
      return {
        formInstance: {
          id: instance.id,
          formKey: instance.formKey,
          formName: instance.definition.name,
          status: instance.status,
          submittedBy: instance.submitter,
          submittedAt: instance.submittedAt,
        },
        approval: null,
        currentTasks: [],
        history: [],
      };
    }

    // 3. 查询审批实例详情
    const approvalInstance = await this.prisma.approvalInstance.findUnique({
      where: { id: instance.approvalInstanceId },
      include: {
        nodeInstances: {
          orderBy: { startTime: 'asc' },
        },
      },
    });

    if (!approvalInstance) {
      this.logger.warn(
        `ApprovalInstance ${instance.approvalInstanceId} not found`,
      );
      return {
        formInstance: {
          id: instance.id,
          formKey: instance.formKey,
          formName: instance.definition.name,
          status: instance.status,
          submittedBy: instance.submitter,
          submittedAt: instance.submittedAt,
        },
        approval: null,
        currentTasks: [],
        history: [],
      };
    }

    // 4. 查询当前任务
    const currentTasks = await this.prisma.approvalTask.findMany({
      where: {
        instanceId: instance.approvalInstanceId,
        status: { in: ['CREATED'] }, // CLAIMED 不是有效的状态
      },
      include: {
        nodeInstance: true,
      },
      orderBy: { createTime: 'asc' },
    });

    // 5. 查询审批历史
    const history = await this.prisma.approvalTaskLog.findMany({
      where: {
        task: {
          instanceId: instance.approvalInstanceId,
        },
      },
      include: {
        task: {
          select: {
            name: true,
          },
        },
      },
      orderBy: { actionTime: 'asc' }, // 修正字段名
    });

    return {
      formInstance: {
        id: instance.id,
        formKey: instance.formKey,
        formName: instance.definition.name,
        status: instance.status,
        submittedBy: instance.submitter,
        submittedAt: instance.submittedAt,
      },
      approval: {
        id: approvalInstance.id,
        status: approvalInstance.status,
        currentNode: approvalInstance.currentNode,
        startTime: approvalInstance.startTime,
        endTime: approvalInstance.endTime,
      },
      currentTasks: currentTasks.map((task) => ({
        id: task.id,
        name: task.name,
        assignee: task.assignee,
        status: task.status,
        createTime: task.createTime,
      })),
      history: history.map((log) => ({
        id: log.id,
        taskName: log.task.name,
        action: log.action,
        actorId: log.operatorId, // 修正字段名
        comment: log.comment,
        timestamp: log.actionTime, // 修正字段名
      })),
    };
  }

  /**
   * 撤回表单（同时撤回审批流）
   * 
   * @param instanceId 表单实例ID
   * @param userId 撤回人ID
   * @returns 更新后的表单实例
   */
  @SkipAssertAccess('方法内手动校验 instance.createdBy === userId（仅发起人可撤回），与 instance.service.ts:withdraw 的 IDOR 防护一致')
  async withdrawFormWithApproval(instanceId: string, userId: string) {
    this.logger.log(`Withdrawing form instance ${instanceId} by user ${userId}`);

    const instance = await this.prisma.formInstance.findUnique({
      where: { id: instanceId },
    });

    if (!instance) {
      throw new NotFoundException(`FormInstance ${instanceId} not found`);
    }

    // 校验权限：只有发起人可以撤回（与 instance.service.ts:withdraw 一致）
    if (instance.createdBy !== userId) {
      throw new ForbiddenException('只有发起人可以撤回');
    }

    // 1. 如果有审批流，先撤回审批
    if (instance.approvalInstanceId) {
      this.logger.log(
        `Withdrawing approval instance ${instance.approvalInstanceId}`,
      );

      try {
        await this.approvalService.withdraw(
          instance.approvalInstanceId,
          {
            reason: '申请人撤回表单',
          },
          userId,
        );
        this.logger.log(
          `Approval instance ${instance.approvalInstanceId} withdrawn`,
        );
      } catch (error) {
        this.logger.error(
          `Failed to withdraw approval instance: ${error.message}`,
        );
        // 继续执行，即使审批流撤回失败
      }
    }

    // 2. 更新表单状态（统一语义：申请人撤回 → WITHDRAWN，CANCELLED 保留给系统强制取消）
    const updated = await this.prisma.formInstance.update({
      where: { id: instanceId },
      data: {
        status: FormInstanceStatus.WITHDRAWN,
        approvalStatus: 'WITHDRAWN',
        approvalEndTime: new Date(),
        updatedAt: new Date(),
      },
    });

    this.logger.log(`FormInstance ${instanceId} withdrawn successfully`);

    return updated;
  }
}

