/**
 * 表单实例服务
 * 完全符合 API 文档规范
 * 支持用户实例和管理员实例管理
 */

import {
  Injectable,
  Logger,
  NotFoundException,
  BadRequestException,
  ForbiddenException,
  Inject,
  forwardRef,
} from '@nestjs/common';
import { PrismaService } from '@core/database/prisma/prisma.service';
import { FormInstanceStatus, Prisma } from '@prisma/client';
import * as XLSX from 'xlsx';

const EXPORT_MAX_ROWS = 50000;
import {
  CreateFormInstanceDto,
  UpdateFormInstanceDto,
  SubmitFormInstanceDto,
  QueryMyFormInstancesDto,
  QueryAllFormInstancesDto,
  BatchUpdateStatusDto,
  ExportFormInstancesDto,
  GetFormInstanceStatsDto,
  CancelFormInstanceDto,
} from '../dto';
import { FormIdentifierResolverService } from './form-identifier-resolver.service';
import { FormApprovalIntegrationService } from './form-approval-integration.service';
import { FormBusinessKeyService } from './form-business-key.service';

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

  constructor(
    private readonly prisma: PrismaService,
    private readonly identifierResolver: FormIdentifierResolverService,
    @Inject(forwardRef(() => FormApprovalIntegrationService))
    private readonly approvalIntegration: FormApprovalIntegrationService,
    private readonly businessKeyService: FormBusinessKeyService,
  ) {}

  // ============================================
  // 用户接口（我的实例）
  // ============================================

  /**
   * 创建表单实例（草稿）
   */
  async create(dto: CreateFormInstanceDto, userId: string) {
    this.logger.log(
      `Creating form instance for form: ${dto.formIdentifier}`
    );

    // 解析表单定义
    const form = await this.identifierResolver.resolveFormDefinition(
      dto.formIdentifier,
      {
        include: {
          versions: dto.version
            ? {
                where: { version: dto.version },
                take: 1,
              }
            : {
                where: { isDefault: true },
                take: 1,
              },
        },
      }
    ) as any;

    if (!form) {
      throw new NotFoundException(`Form "${dto.formIdentifier}" not found`);
    }

    if (!form.versions || form.versions.length === 0) {
      throw new NotFoundException(
        `No ${dto.version ? `version ${dto.version}` : 'default version'} found for form "${dto.formIdentifier}"`
      );
    }

    const version = form.versions[0];

    // 生成业务单号
    const businessKey = await this.businessKeyService.generateBusinessKey(form.key);

    // 创建实例
    const instance = await this.prisma.formInstance.create({
      data: {
        formDefinitionId: form.id,
        formVersionId: version.id,
        formKey: form.key,
        formVersion: version.version,
        businessKey, // 🆕 业务单号
        data: dto.data,
        status: FormInstanceStatus.DRAFT, // 应用层默认值
        createdBy: userId,
      },
      include: {
        definition: {
          select: {
            key: true,
            slug: true,
            name: true,
            category: true,
          },
        },
        version: {
          select: {
            version: true,
            nameI18n: true,
          },
        },
      },
    });

    this.logger.log(`Form instance created: ${instance.id}`);
    return this.formatInstanceResponse(instance);
  }

  /**
   * 获取我的表单实例列表
   */
  async findMy(query: QueryMyFormInstancesDto, userId: string) {
    const { formKey, status, startDate, endDate, page = 1, limit = 20 } = query;

    const where: Prisma.FormInstanceWhereInput = {
      createdBy: userId,
      deletedAt: null,
    };

    if (formKey) {
      where.formKey = formKey;
    }

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

    if (startDate || endDate) {
      where.createdAt = {};
      if (startDate) {
        where.createdAt.gte = new Date(startDate);
      }
      if (endDate) {
        where.createdAt.lte = new Date(endDate);
      }
    }

    const [items, total] = await Promise.all([
      this.prisma.formInstance.findMany({
        where,
        skip: (page - 1) * limit,
        take: limit,
        orderBy: { createdAt: 'desc' },
        include: {
          definition: {
            select: {
              key: true,
              slug: true,
              name: true,
              category: true,
            },
          },
          version: {
            select: {
              version: true,
              nameI18n: true,
            },
          },
        },
      }),
      this.prisma.formInstance.count({ where }),
    ]);

    return {
      items: items.map((item) => this.formatInstanceResponse(item)),
      total,
      page,
      limit,
      totalPages: Math.ceil(total / limit),
    };
  }

  /**
   * 获取单个实例（我的）
   */
  async findOne(instanceIdentifier: string, userId: string) {
    const instance = await this.identifierResolver.resolveFormInstance(
      instanceIdentifier
    );

    // 检查权限
    if (instance.createdBy !== userId) {
      throw new ForbiddenException('You can only view your own instances');
    }

    const fullInstance = await this.prisma.formInstance.findUnique({
      where: { id: instance.id },
      include: {
        definition: {
          select: {
            key: true,
            slug: true,
            name: true,
            category: true,
            requiresApproval: true,
            approvalProcessKey: true,
          },
        },
        version: {
          select: {
            version: true,
            schema: true,
            uiSchema: true,
            validation: true,
            nameI18n: true,
            descriptionI18n: true,
          },
        },
      },
    });

    return this.formatInstanceResponse(fullInstance);
  }

  /**
   * 更新表单实例（草稿）
   */
  async update(
    instanceIdentifier: string,
    dto: UpdateFormInstanceDto,
    userId: string
  ) {
    this.logger.log(`Updating form instance: ${instanceIdentifier}`);

    const instance = await this.identifierResolver.resolveFormInstance(
      instanceIdentifier
    );

    // 检查权限
    if (instance.createdBy !== userId) {
      throw new ForbiddenException('You can only update your own instances');
    }

    // 只能更新草稿状态的实例
    if (instance.status !== FormInstanceStatus.DRAFT) {
      throw new BadRequestException(
        `Cannot update instance because it is ${instance.status}`
      );
    }

    const updated = await this.prisma.formInstance.update({
      where: { id: instance.id },
      data: {
        data: dto.data,
        updatedBy: userId,
      },
      include: {
        definition: {
          select: {
            key: true,
            slug: true,
            name: true,
          },
        },
        version: {
          select: {
            version: true,
            nameI18n: true,
          },
        },
      },
    });

    this.logger.log(`Form instance updated: ${updated.id}`);
    return this.formatInstanceResponse(updated);
  }

  /**
   * 提交表单实例
   */
  async submit(
    instanceIdentifier: string,
    dto: SubmitFormInstanceDto,
    userId: string
  ) {
    this.logger.log(`Submitting form instance: ${instanceIdentifier}`);

    const instance = await this.identifierResolver.resolveFormInstance(
      instanceIdentifier
    );

    // 检查权限
    if (instance.createdBy !== userId) {
      throw new ForbiddenException('You can only submit your own instances');
    }

    // 只能提交草稿状态的实例
    if (instance.status !== FormInstanceStatus.DRAFT) {
      throw new BadRequestException(
        `Cannot submit instance because it is already ${instance.status}`
      );
    }

    // 获取表单定义
    const form = await this.prisma.formDefinition.findUnique({
      where: { id: instance.formDefinitionId },
    });

    if (!form) {
      throw new NotFoundException('Form definition not found');
    }

    // 更新数据
    const updatedInstance = await this.prisma.formInstance.update({
      where: { id: instance.id },
      data: {
        data: dto.data,
        submittedBy: userId,
        submittedAt: new Date(),
        // 状态将由审批集成服务决定
      },
    });

    // 启动审批流（如果需要）
    let approvalResult: any = null;
    if (form.requiresApproval && form.approvalProcessKey && dto.submitForApproval !== false) {
      this.logger.log(`Form requires approval, starting approval workflow...`);
      try {
        approvalResult = await this.approvalIntegration.submitWithApproval(
          updatedInstance,
          form,
          userId,
          dto.comment,
        );
      } catch (error) {
        this.logger.error(`Failed to start approval: ${error.message}`);
        // 如果启动审批失败，仍然标记为已提交
        await this.prisma.formInstance.update({
          where: { id: instance.id },
          data: { status: FormInstanceStatus.SUBMITTED },
        });
        throw error;
      }
    } else {
      // 不需要审批，直接标记为已提交
      await this.prisma.formInstance.update({
        where: { id: instance.id },
        data: { status: FormInstanceStatus.SUBMITTED },
      });
    }

    // 重新查询包含完整关联数据
    const submitted = await this.prisma.formInstance.findUnique({
      where: { id: instance.id },
      include: {
        definition: {
          select: {
            key: true,
            slug: true,
            name: true,
            category: true,
          },
        },
        version: {
          select: {
            version: true,
            nameI18n: true,
          },
        },
      },
    });

    if (!submitted) {
      throw new NotFoundException('Form instance not found after submission');
    }

    this.logger.log(`Form instance submitted: ${submitted.id}, approval: ${approvalResult?.needsApproval ? 'started' : 'not required'}`);
    
    return {
      ...this.formatInstanceResponse(submitted),
      approval: approvalResult?.needsApproval ? approvalResult.approvalInstance : null,
    };
  }

  /**
   * 删除表单实例（软删除）
   */
  async remove(instanceIdentifier: string, userId: string) {
    this.logger.log(`Deleting form instance: ${instanceIdentifier}`);

    const instance = await this.identifierResolver.resolveFormInstance(
      instanceIdentifier
    );

    // 检查权限
    if (instance.createdBy !== userId) {
      throw new ForbiddenException('You can only delete your own instances');
    }

    // 只能删除草稿状态的实例
    if (instance.status !== FormInstanceStatus.DRAFT) {
      throw new BadRequestException(
        `Cannot delete instance because it is ${instance.status}`
      );
    }

    await this.prisma.formInstance.update({
      where: { id: instance.id },
      data: {
        deletedAt: new Date(),
      },
    });

    this.logger.log(`Form instance deleted: ${instance.id}`);
    return {
      id: instance.id,
      deleted: true,
    };
  }

  /**
   * 取消表单实例
   */
  async cancel(
    instanceIdentifier: string,
    dto: CancelFormInstanceDto,
    userId: string
  ) {
    this.logger.log(`Cancelling form instance: ${instanceIdentifier}`);

    const instance = await this.identifierResolver.resolveFormInstance(
      instanceIdentifier
    );

    // 检查权限
    if (instance.createdBy !== userId) {
      throw new ForbiddenException('You can only cancel your own instances');
    }

    // 只能取消已提交的实例
    if (instance.status !== FormInstanceStatus.SUBMITTED) {
      throw new BadRequestException(
        `Cannot cancel instance because it is ${instance.status}`
      );
    }

    const cancelled = await this.prisma.formInstance.update({
      where: { id: instance.id },
      data: {
        status: FormInstanceStatus.CANCELLED,
        data: {
          ...(instance.data as object),
          _cancelReason: dto.reason,
          _cancelledAt: new Date().toISOString(),
        },
      },
      include: {
        definition: {
          select: {
            key: true,
            slug: true,
            name: true,
          },
        },
      },
    });

    this.logger.log(`Form instance cancelled: ${cancelled.id}`);
    return this.formatInstanceResponse(cancelled);
  }

  /**
   * 恢复已删除的实例 🆕
   */
  async restore(instanceIdentifier: string, userId: string) {
    this.logger.log(`Restoring form instance: ${instanceIdentifier}`);

    // 查找包括已删除的实例
    const instance = await this.prisma.formInstance.findFirst({
      where: {
        OR: [
          { id: instanceIdentifier },
          { businessKey: instanceIdentifier },
        ],
      },
    });

    if (!instance) {
      throw new NotFoundException(
        `Form instance "${instanceIdentifier}" not found`
      );
    }

    if (!instance.deletedAt) {
      throw new BadRequestException(
        'Instance is not deleted, no need to restore'
      );
    }

    const restored = await this.prisma.formInstance.update({
      where: { id: instance.id },
      data: {
        deletedAt: null,
        updatedBy: userId,
      },
    });

    this.logger.log(`Form instance restored: ${restored.id}`);
    return {
      id: restored.id,
      businessKey: restored.businessKey,
      deletedAt: null,
      restored: true,
    };
  }

  // ============================================
  // 管理员接口（所有实例）
  // ============================================

  /**
   * 获取所有表单实例（管理员）
   */
  async findAll(query: QueryAllFormInstancesDto) {
    const {
      formKey,
      status,
      createdBy,
      startDate,
      endDate,
      includeDeleted = false,
      page = 1,
      limit = 20,
    } = query;

    const where: Prisma.FormInstanceWhereInput = {};

    if (formKey) {
      where.formKey = formKey;
    }

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

    if (createdBy) {
      where.createdBy = createdBy;
    }

    if (startDate || endDate) {
      where.createdAt = {};
      if (startDate) {
        where.createdAt.gte = new Date(startDate);
      }
      if (endDate) {
        where.createdAt.lte = new Date(endDate);
      }
    }

    if (!includeDeleted) {
      where.deletedAt = null;
    }

    const [items, total] = await Promise.all([
      this.prisma.formInstance.findMany({
        where,
        skip: (page - 1) * limit,
        take: limit,
        orderBy: { createdAt: 'desc' },
        include: {
          definition: {
            select: {
              key: true,
              slug: true,
              name: true,
              category: true,
            },
          },
          version: {
            select: {
              version: true,
              nameI18n: true,
            },
          },
          creator: { select: { id: true, displayName: true,
            },
          },
          submitter: { select: { id: true, displayName: true,
            },
          },
        },
      }),
      this.prisma.formInstance.count({ where }),
    ]);

    return {
      items: items.map((item) => this.formatInstanceResponse(item)),
      total,
      page,
      limit,
      totalPages: Math.ceil(total / limit),
    };
  }

  /**
   * 批量更新实例状态（管理员）
   */
  async batchUpdateStatus(dto: BatchUpdateStatusDto) {
    this.logger.log(
      `Batch updating ${dto.instanceIds.length} instances to ${dto.status}`
    );

    const updated = await this.prisma.formInstance.updateMany({
      where: {
        id: { in: dto.instanceIds },
        deletedAt: null,
      },
      data: {
        status: dto.status,
      },
    });

    this.logger.log(`Batch updated ${updated.count} instances`);
    return {
      updated: updated.count,
      failed: dto.instanceIds.length - updated.count,
    };
  }

  /**
   * 导出表单实例数据（管理员）
   */
  async exportInstances(dto: ExportFormInstancesDto) {
    this.logger.log(`Exporting instances for form: ${dto.formKey}`);

    const where: Prisma.FormInstanceWhereInput = {
      formKey: dto.formKey,
      deletedAt: null,
    };

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

    if (dto.startDate || dto.endDate) {
      where.createdAt = {};
      if (dto.startDate) {
        where.createdAt.gte = new Date(dto.startDate);
      }
      if (dto.endDate) {
        where.createdAt.lte = new Date(dto.endDate);
      }
    }

    const instances = await this.prisma.formInstance.findMany({
      where,
      orderBy: { createdAt: 'desc' },
      take: EXPORT_MAX_ROWS,
      include: {
        creator: { select: { displayName: true } },
        submitter: { select: { displayName: true } },
      },
    });

    if (instances.length === EXPORT_MAX_ROWS) {
      this.logger.warn(
        `Export hit ${EXPORT_MAX_ROWS} row cap for formKey=${dto.formKey}; output truncated`,
      );
    }
    this.logger.log(`Exporting ${instances.length} instances`);

    const format: 'excel' | 'csv' = dto.format || 'excel';
    const rows = instances.map((it: any) => ({
      ID: it.id,
      业务编号: it.businessKey ?? '',
      标题: it.title ?? '',
      状态: it.status,
      审批状态: it.approvalStatus ?? '',
      创建人: it.creator?.displayName ?? it.createdBy,
      提交人: it.submitter?.displayName ?? it.submittedBy ?? '',
      创建时间: it.createdAt?.toISOString() ?? '',
      提交时间: it.submittedAt?.toISOString() ?? '',
      审批结束时间: it.approvalEndTime?.toISOString() ?? '',
      数据: this.flattenJsonForCell(it.data),
    }));

    const worksheet = XLSX.utils.json_to_sheet(rows);
    const buffer: Buffer =
      format === 'csv'
        ? Buffer.from(XLSX.utils.sheet_to_csv(worksheet), 'utf-8')
        : XLSX.write(
            (() => {
              const wb = XLSX.utils.book_new();
              XLSX.utils.book_append_sheet(wb, worksheet, 'instances');
              return wb;
            })(),
            { type: 'buffer', bookType: 'xlsx' },
          );

    return {
      format,
      filename: `form-instances-${dto.formKey}-${Date.now()}.${format === 'csv' ? 'csv' : 'xlsx'}`,
      buffer,
      rowCount: instances.length,
    };
  }

  private flattenJsonForCell(data: any): string {
    if (data == null) return '';
    if (typeof data === 'string') return data;
    return JSON.stringify(data);
  }

  /**
   * 获取表单实例统计（管理员）
   */
  async getStats(dto: GetFormInstanceStatsDto) {
    const form = await this.identifierResolver.resolveFormDefinition(
      dto.formKey
    ) as any;

    if (!form) {
      throw new NotFoundException(`Form not found`);
    }

    const where: Prisma.FormInstanceWhereInput = {
      formDefinitionId: form.id,
      deletedAt: null,
    };

    if (dto.startDate || dto.endDate) {
      where.createdAt = {};
      if (dto.startDate) {
        where.createdAt.gte = new Date(dto.startDate);
      }
      if (dto.endDate) {
        where.createdAt.lte = new Date(dto.endDate);
      }
    }

    const [
      totalInstances,
      statusBreakdown,
      submissionTrend,
      topUsers,
    ] = await Promise.all([
      this.prisma.formInstance.count({ where }),
      this.getStatusBreakdown(form.id, dto),
      this.getSubmissionTrend(form.id, dto),
      this.getTopUsers(form.id, dto),
    ]);

    return {
      formKey: dto.formKey,
      totalInstances,
      statusBreakdown,
      submissionTrend,
      topUsers,
    };
  }

  // ============================================
  // 私有辅助方法
  // ============================================

  /**
   * 获取状态分布
   */
  private async getStatusBreakdown(
    formDefinitionId: string,
    dto: GetFormInstanceStatsDto
  ) {
    const where: Prisma.FormInstanceWhereInput = {
      formDefinitionId,
      deletedAt: null,
    };

    if (dto.startDate || dto.endDate) {
      where.createdAt = {};
      if (dto.startDate) {
        where.createdAt.gte = new Date(dto.startDate);
      }
      if (dto.endDate) {
        where.createdAt.lte = new Date(dto.endDate);
      }
    }

    const [
      draftCount,
      submittedCount,
      approvedCount,
      rejectedCount,
      cancelledCount,
    ] = await Promise.all([
      this.prisma.formInstance.count({
        where: { ...where, status: FormInstanceStatus.DRAFT },
      }),
      this.prisma.formInstance.count({
        where: { ...where, status: FormInstanceStatus.SUBMITTED },
      }),
      this.prisma.formInstance.count({
        where: { ...where, status: FormInstanceStatus.APPROVED },
      }),
      this.prisma.formInstance.count({
        where: { ...where, status: FormInstanceStatus.REJECTED },
      }),
      this.prisma.formInstance.count({
        where: { ...where, status: FormInstanceStatus.CANCELLED },
      }),
    ]);

    return {
      DRAFT: draftCount,
      SUBMITTED: submittedCount,
      APPROVED: approvedCount,
      REJECTED: rejectedCount,
      CANCELLED: cancelledCount,
    };
  }

  /**
   * 获取提交趋势：按 day / week / month / user 聚合实例数。
   * 默认 day。SQL 用 date_trunc / user_id GROUP BY，避免拉全量到 JS 层。
   */
  private async getSubmissionTrend(
    formDefinitionId: string,
    dto: GetFormInstanceStatsDto,
  ): Promise<Array<{ bucket: string; count: number }>> {
    const groupBy = dto.groupBy ?? 'day';
    const start = dto.startDate ? new Date(dto.startDate) : null;
    const end = dto.endDate ? new Date(dto.endDate) : null;

    if (groupBy === 'user') {
      const rows = await this.prisma.formInstance.groupBy({
        by: ['createdBy'],
        where: {
          formDefinitionId,
          deletedAt: null,
          ...(start || end
            ? {
                createdAt: {
                  ...(start ? { gte: start } : {}),
                  ...(end ? { lte: end } : {}),
                },
              }
            : {}),
        },
        _count: { _all: true },
        orderBy: { _count: { id: 'desc' } },
        take: 50,
      });
      return rows.map((r) => ({
        bucket: r.createdBy,
        count: r._count._all,
      }));
    }

    // day / week / month: 用 date_trunc，PostgreSQL 原生支持
    const truncUnit =
      groupBy === 'month' ? 'month' : groupBy === 'week' ? 'week' : 'day';

    const conditions: Prisma.Sql[] = [
      Prisma.sql`form_definition_id = ${formDefinitionId}::uuid`,
      Prisma.sql`deleted_at IS NULL`,
    ];
    if (start) conditions.push(Prisma.sql`created_at >= ${start}`);
    if (end) conditions.push(Prisma.sql`created_at <= ${end}`);
    const whereSql = Prisma.join(conditions, ' AND ');

    const rows = await this.prisma.$queryRaw<
      Array<{ bucket: Date; count: bigint }>
    >(
      Prisma.sql`
        SELECT date_trunc(${truncUnit}, created_at) AS bucket, COUNT(*)::bigint AS count
        FROM platform_form.form_instances
        WHERE ${whereSql}
        GROUP BY bucket
        ORDER BY bucket ASC
      `,
    );

    return rows.map((r) => ({
      bucket: r.bucket.toISOString(),
      count: Number(r.count),
    }));
  }

  /**
   * 获取 Top 用户
   */
  private async getTopUsers(
    formDefinitionId: string,
    dto: GetFormInstanceStatsDto
  ) {
    const where: Prisma.FormInstanceWhereInput = {
      formDefinitionId,
      deletedAt: null,
    };

    if (dto.startDate || dto.endDate) {
      where.createdAt = {};
      if (dto.startDate) {
        where.createdAt.gte = new Date(dto.startDate);
      }
      if (dto.endDate) {
        where.createdAt.lte = new Date(dto.endDate);
      }
    }

    const topUsers = await this.prisma.formInstance.groupBy({
      by: ['createdBy'],
      where,
      _count: {
        id: true,
      },
      orderBy: {
        _count: {
          id: 'desc',
        },
      },
      take: 10,
    });

    return topUsers.map((user) => ({
      userId: user.createdBy,
      count: user._count.id,
    }));
  }

  /**
   * 格式化实例响应
   */
  private formatInstanceResponse(instance: any) {
    const { definition, version, creator, submitter, ...instanceData } =
      instance;

    return {
      ...instanceData,
      form: definition
        ? {
            key: definition.key,
            slug: definition.slug,
            name: definition.name,
            category: definition.category,
          }
        : undefined,
      version: version
        ? {
            version: version.version,
            nameI18n: version.nameI18n,
          }
        : undefined,
      creator: creator
        ? {
            id: creator.id,
            username: creator.username,
            displayName: creator.displayName,
          }
        : undefined,
      submitter: submitter
        ? {
            id: submitter.id,
            username: submitter.username,
            displayName: submitter.displayName,
          }
        : undefined,
    };
  }
}

