/**
 * 表单版本服务
 * 完全符合 API 文档规范 v2.0
 * 支持版本审核流程（DRAFT -> PENDING_REVIEW -> PUBLISHED/REJECTED）
 */

import {
  Injectable,
  Logger,
  NotFoundException,
  BadRequestException,
} from '@nestjs/common';
import { PrismaService } from '@core/database/prisma/prisma.service';
import { FormVersionStatus, Prisma } from '@prisma/client';
import {
  CreateFormVersionDto,
  UpdateFormVersionDto,
  PublishFormVersionDto,
  SetDefaultVersionDto,
} from '../dto';
import {
  SubmitForReviewDto,
  ReviewVersionDto,
  ReviewAction,
  QueryPendingReviewDto,
  QueryMySubmissionsDto,
  ReviewSubmissionStatus,
} from '../dto/form-version-review.dto';
import { FormIdentifierResolverService } from './form-identifier-resolver.service';

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

  constructor(
    private readonly prisma: PrismaService,
    private readonly identifierResolver: FormIdentifierResolverService
  ) {}

  // ============================================
  // 1. 创建新版本
  // ============================================

  async create(
    formIdentifier: string,
    dto: CreateFormVersionDto,
    createdBy: string
  ) {
    this.logger.log(`Creating new version for form: ${formIdentifier}`);

    const form = await this.identifierResolver.resolveFormDefinition(
      formIdentifier,
      {
        include: {
          versions: {
            orderBy: { version: 'desc' },
            take: 1,
          },
        },
      }
    ) as any;

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

    const nextVersion = (form.versions?.[0]?.version || 0) + 1;

    // 如果设置为默认版本，先取消其他版本的默认状态
    if (dto.setAsDefault) {
      await this.prisma.formVersion.updateMany({
        where: {
          definitionId: form.id,
          isDefault: true,
        },
        data: {
          isDefault: false,
        },
      });
    }

    const version = await this.prisma.formVersion.create({
      data: {
        definitionId: form.id,
        version: nextVersion,
        schema: dto.schema,
        uiSchema: dto.uiSchema,
        validation: dto.validation,
        nameI18n: dto.nameI18n,
        descriptionI18n: dto.descriptionI18n,
        changelog: dto.changelog,
        status: FormVersionStatus.DRAFT, // 应用层默认值
        isDefault: dto.setAsDefault || false, // 应用层默认值
        createdBy,
      },
    });

    // 创建翻译数据（如果提供了）
    if (dto.translations) {
      const translationPromises = Object.entries(dto.translations).map(
        ([locale, translations]) =>
          this.prisma.formTranslation.create({
            data: {
              versionId: version.id,
              locale,
              translations,
            },
          })
      );
      await Promise.all(translationPromises);
    }

    // 更新表单定义的最新版本号
    await this.prisma.formDefinition.update({
      where: { id: form.id },
      data: { latestVersion: nextVersion },
    });

    this.logger.log(`New version created: ${version.id}`);
    return version;
  }

  // ============================================
  // 2. 获取所有版本
  // ============================================

  async findAll(formIdentifier: string) {
    const form = await this.identifierResolver.resolveFormDefinition(formIdentifier
    ) as any;

    const versions = await this.prisma.formVersion.findMany({
      where: { definitionId: form.id },
      orderBy: { version: 'desc' },
      include: {
        _count: {
          select: {
            instances: true,
            translations: true,
          },
        },
      },
    });

    return versions.map((version) => ({
      ...version,
      instanceCount: version._count.instances,
      translationCount: version._count.translations,
      _count: undefined,
    }));
  }

  // ============================================
  // 3. 获取指定版本
  // ============================================

  async findOne(formIdentifier: string, version: number) {
    const form = await this.identifierResolver.resolveFormDefinition(formIdentifier
    ) as any;

    const formVersion = await this.prisma.formVersion.findFirst({
      where: {
        definitionId: form.id,
        version,
      },
      include: {
        translations: true,
        _count: {
          select: {
            instances: true,
          },
        },
      },
    });

    if (!formVersion) {
      throw new NotFoundException(
        `Version ${version} not found for form "${formIdentifier}"`
      );
    }

    return {
      ...formVersion,
      instanceCount: formVersion._count.instances,
      _count: undefined,
    };
  }

  // ============================================
  // 4. 更新版本
  // ============================================

  async update(
    formIdentifier: string,
    version: number,
    dto: UpdateFormVersionDto
  ) {
    this.logger.log(
      `Updating version ${version} for form: ${formIdentifier}`
    );

    const form = await this.identifierResolver.resolveFormDefinition(formIdentifier
    ) as any;

    const existingVersion = await this.prisma.formVersion.findFirst({
      where: {
        definitionId: form.id,
        version,
      },
    });

    if (!existingVersion) {
      throw new NotFoundException(
        `Version ${version} not found for form "${formIdentifier}"`
      );
    }

    // 只能更新草稿版本
    if (existingVersion.status !== FormVersionStatus.DRAFT) {
      throw new BadRequestException(
        `Cannot update version ${version} because it is already published`
      );
    }

    const updated = await this.prisma.formVersion.update({
      where: { id: existingVersion.id },
      data: dto,
      include: {
        translations: true,
        _count: {
          select: {
            instances: true,
          },
        },
      },
    });

    this.logger.log(`Version updated: ${updated.id}`);
    return {
      ...updated,
      instanceCount: updated._count.instances,
      _count: undefined,
    };
  }

  // ============================================
  // 5. 发布版本
  // ============================================

  async publish(
    formIdentifier: string,
    version: number,
    dto?: PublishFormVersionDto
  ) {
    this.logger.log(
      `Publishing version ${version} for form: ${formIdentifier}`
    );

    const form = await this.identifierResolver.resolveFormDefinition(formIdentifier
    ) as any;

    const existingVersion = await this.prisma.formVersion.findFirst({
      where: {
        definitionId: form.id,
        version,
      },
    });

    if (!existingVersion) {
      throw new NotFoundException(
        `Version ${version} not found for form "${formIdentifier}"`
      );
    }

    // 如果设置为默认版本，先取消其他版本的默认状态
    if (dto?.setAsDefault) {
      await this.prisma.formVersion.updateMany({
        where: {
          definitionId: form.id,
          isDefault: true,
        },
        data: {
          isDefault: false,
        },
      });
    }

    const published = await this.prisma.formVersion.update({
      where: { id: existingVersion.id },
      data: {
        status: FormVersionStatus.PUBLISHED,
        isDefault: dto?.setAsDefault || existingVersion.isDefault,
      },
    });

    this.logger.log(`Version published: ${published.id}`);
    return published;
  }

  // ============================================
  // 6. 废弃版本
  // ============================================

  async deprecate(formIdentifier: string, version: number) {
    this.logger.log(
      `Deprecating version ${version} for form: ${formIdentifier}`
    );

    const form = await this.identifierResolver.resolveFormDefinition(formIdentifier
    ) as any;

    const existingVersion = await this.prisma.formVersion.findFirst({
      where: {
        definitionId: form.id,
        version,
      },
    });

    if (!existingVersion) {
      throw new NotFoundException(
        `Version ${version} not found for form "${formIdentifier}"`
      );
    }

    // 不能废弃默认版本
    if (existingVersion.isDefault) {
      throw new BadRequestException(
        `Cannot deprecate version ${version} because it is the default version`
      );
    }

    const deprecated = await this.prisma.formVersion.update({
      where: { id: existingVersion.id },
      data: {
        status: FormVersionStatus.DEPRECATED,
      },
    });

    this.logger.log(`Version deprecated: ${deprecated.id}`);
    return deprecated;
  }

  // ============================================
  // 7. 设置默认版本
  // ============================================

  async setDefault(formIdentifier: string, dto: SetDefaultVersionDto) {
    this.logger.log(
      `Setting version ${dto.version} as default for form: ${formIdentifier}`
    );

    const form = await this.identifierResolver.resolveFormDefinition(formIdentifier
    ) as any;

    const version = await this.prisma.formVersion.findFirst({
      where: {
        definitionId: form.id,
        version: dto.version,
      },
    });

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

    // 版本必须是已发布状态
    if (version.status !== FormVersionStatus.PUBLISHED) {
      throw new BadRequestException(
        `Version ${dto.version} must be published before setting as default`
      );
    }

    // 取消其他版本的默认状态
    await this.prisma.formVersion.updateMany({
      where: {
        definitionId: form.id,
        isDefault: true,
      },
      data: {
        isDefault: false,
      },
    });

    // 设置新的默认版本
    const updated = await this.prisma.formVersion.update({
      where: { id: version.id },
      data: {
        isDefault: true,
      },
    });

    this.logger.log(`Default version set: ${updated.id}`);
    return updated;
  }

  // ============================================
  // 8. 删除版本
  // ============================================

  async remove(formIdentifier: string, version: number) {
    this.logger.log(
      `Deleting version ${version} for form: ${formIdentifier}`
    );

    const form = await this.identifierResolver.resolveFormDefinition(formIdentifier
    ) as any;

    const existingVersion = await this.prisma.formVersion.findFirst({
      where: {
        definitionId: form.id,
        version,
      },
      include: {
        _count: {
          select: {
            instances: true,
          },
        },
      },
    });

    if (!existingVersion) {
      throw new NotFoundException(
        `Version ${version} not found for form "${formIdentifier}"`
      );
    }

    // 检查是否有实例使用此版本
    if (existingVersion._count.instances > 0) {
      throw new BadRequestException(
        `Cannot delete version ${version} because it has ${existingVersion._count.instances} instances`
      );
    }

    // 不能删除默认版本
    if (existingVersion.isDefault) {
      throw new BadRequestException(
        `Cannot delete version ${version} because it is the default version`
      );
    }

    await this.prisma.formVersion.delete({
      where: { id: existingVersion.id },
    });

    this.logger.log(`Version deleted: ${existingVersion.id}`);
    return {
      id: existingVersion.id,
      version: existingVersion.version,
      deleted: true,
    };
  }

  // ============================================
  // 9. 提交审核 🆕
  // ============================================

  async submitForReview(
    formIdentifier: string,
    version: number,
    dto: SubmitForReviewDto,
    userId: string
  ) {
    this.logger.log(
      `Submitting version ${version} for review: ${formIdentifier}`
    );

    const form = await this.identifierResolver.resolveFormDefinition(
      formIdentifier
    ) as any;

    const existingVersion = await this.prisma.formVersion.findFirst({
      where: {
        definitionId: form.id,
        version,
      },
    });

    if (!existingVersion) {
      throw new NotFoundException(
        `Version ${version} not found for form "${formIdentifier}"`
      );
    }

    // 只能提交草稿或已驳回的版本
    if (
      existingVersion.status !== FormVersionStatus.DRAFT &&
      existingVersion.status !== FormVersionStatus.REJECTED
    ) {
      throw new BadRequestException(
        `Cannot submit version ${version} for review because it is ${existingVersion.status}`
      );
    }

    const updated = await this.prisma.formVersion.update({
      where: { id: existingVersion.id },
      data: {
        status: FormVersionStatus.PENDING_REVIEW,
        // 记录提交信息到 changelog 或 metadata
        changelog: dto.comment
          ? `${existingVersion.changelog || ''}\n[${new Date().toISOString()}] 提交审核: ${dto.comment}`.trim()
          : existingVersion.changelog,
      },
    });

    this.logger.log(`Version submitted for review: ${updated.id}`);
    return {
      id: updated.id,
      version: updated.version,
      status: updated.status,
      submittedAt: new Date().toISOString(),
    };
  }

  // ============================================
  // 10. 审核版本（通过/驳回）🆕
  // ============================================

  async reviewVersion(
    formIdentifier: string,
    version: number,
    dto: ReviewVersionDto,
    reviewerId: string
  ) {
    this.logger.log(
      `Reviewing version ${version} for form: ${formIdentifier}, action: ${dto.action}`
    );

    const form = await this.identifierResolver.resolveFormDefinition(
      formIdentifier
    ) as any;

    const existingVersion = await this.prisma.formVersion.findFirst({
      where: {
        definitionId: form.id,
        version,
      },
    });

    if (!existingVersion) {
      throw new NotFoundException(
        `Version ${version} not found for form "${formIdentifier}"`
      );
    }

    // 只能审核待审核状态的版本
    if (existingVersion.status !== FormVersionStatus.PENDING_REVIEW) {
      throw new BadRequestException(
        `Cannot review version ${version} because it is ${existingVersion.status}, expected PENDING_REVIEW`
      );
    }

    const now = new Date();

    if (dto.action === ReviewAction.APPROVE) {
      // 审核通过
      // 如果设置为默认版本，先取消其他版本的默认状态
      if (dto.setAsDefault) {
        await this.prisma.formVersion.updateMany({
          where: {
            definitionId: form.id,
            isDefault: true,
          },
          data: {
            isDefault: false,
          },
        });
      }

      const approved = await this.prisma.formVersion.update({
        where: { id: existingVersion.id },
        data: {
          status: FormVersionStatus.PUBLISHED,
          isDefault: dto.setAsDefault || existingVersion.isDefault,
          reviewedBy: reviewerId,
          reviewedAt: now,
          reviewComment: dto.comment,
          publishedAt: now,
        },
      });

      this.logger.log(`Version approved: ${approved.id}`);
      return {
        id: approved.id,
        version: approved.version,
        status: approved.status,
        isDefault: approved.isDefault,
        reviewedBy: reviewerId,
        reviewedAt: now.toISOString(),
        reviewComment: dto.comment,
      };
    } else {
      // 审核驳回
      const rejected = await this.prisma.formVersion.update({
        where: { id: existingVersion.id },
        data: {
          status: FormVersionStatus.REJECTED,
          reviewedBy: reviewerId,
          reviewedAt: now,
          reviewComment: dto.comment,
        },
      });

      this.logger.log(`Version rejected: ${rejected.id}`);
      return {
        id: rejected.id,
        version: rejected.version,
        status: rejected.status,
        reviewedBy: reviewerId,
        reviewedAt: now.toISOString(),
        reviewComment: dto.comment,
      };
    }
  }

  // ============================================
  // 11. 获取待审核列表 🆕
  // ============================================

  async findPendingReview(query: QueryPendingReviewDto) {
    const { category, submittedBy, page = 1, limit = 20 } = query;

    const where: Prisma.FormVersionWhereInput = {
      status: FormVersionStatus.PENDING_REVIEW,
    };

    if (category) {
      where.definition = {
        category,
      };
    }

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

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

    return {
      items: items.map((item) => ({
        id: item.id,
        version: item.version,
        status: item.status,
        changelog: item.changelog,
        createdAt: item.createdAt,
        submittedBy: item.creator
          ? {
              id: item.creator.id,
              name: item.creator.displayName,
            }
          : null,
        form: item.definition
          ? {
              id: item.definition.id,
              key: item.definition.key,
              slug: item.definition.slug,
              name: item.definition.name,
              category: item.definition.category,
            }
          : null,
      })),
      total,
      page,
      limit,
      totalPages: Math.ceil(total / limit),
    };
  }

  // ============================================
  // 12. 预览待审核表单 🆕
  // ============================================

  async previewForReview(versionId: string) {
    const version = await this.prisma.formVersion.findUnique({
      where: { id: versionId },
      include: {
        definition: {
          select: {
            id: true,
            key: true,
            slug: true,
            name: true,
            category: true,
          },
        },
        translations: true,
      },
    });

    if (!version) {
      throw new NotFoundException(`Version not found: ${versionId}`);
    }

    // 获取前一个版本用于对比
    const previousVersion = await this.prisma.formVersion.findFirst({
      where: {
        definitionId: version.definitionId,
        version: { lt: version.version },
      },
      orderBy: { version: 'desc' },
      select: {
        version: true,
        schema: true,
      },
    });

    // 简单的字段对比逻辑
    let diff = null;
    if (previousVersion) {
      diff = this.compareSchemas(
        previousVersion.schema as any,
        version.schema as any
      );
    }

    return {
      version: {
        id: version.id,
        version: version.version,
        schema: version.schema,
        uiSchema: version.uiSchema,
        viewSchema: version.viewSchema,
        changelog: version.changelog,
        status: version.status,
      },
      form: version.definition,
      translations: version.translations.reduce(
        (acc, t) => {
          acc[t.locale] = t.translations;
          return acc;
        },
        {} as Record<string, any>
      ),
      previousVersion: previousVersion
        ? {
            version: previousVersion.version,
            schema: previousVersion.schema,
          }
        : null,
      diff,
    };
  }

  // ============================================
  // 13. 获取审核历史 🆕
  // ============================================

  async getReviewHistory(versionId: string) {
    const version = await this.prisma.formVersion.findUnique({
      where: { id: versionId },
      include: {
        reviewer: {
          select: {
            id: true,
            displayName: true,
          },
        },
        creator: {
          select: {
            id: true,
            displayName: true,
          },
        },
      },
    });

    if (!version) {
      throw new NotFoundException(`Version not found: ${versionId}`);
    }

    // 从 changelog 和审核记录构建历史
    // 这里简化处理，实际可能需要专门的审核历史表
    const history = [];

    // 创建记录
    history.push({
      action: 'create',
      operator: version.creator
        ? { id: version.creator.id, name: version.creator.displayName }
        : null,
      comment: null,
      timestamp: version.createdAt.toISOString(),
    });

    // 如果有审核记录
    if (version.reviewedBy && version.reviewedAt) {
      const action =
        version.status === FormVersionStatus.PUBLISHED
          ? 'approve'
          : version.status === FormVersionStatus.REJECTED
            ? 'reject'
            : 'review';

      history.push({
        action,
        operator: version.reviewer
          ? { id: version.reviewer.id, name: version.reviewer.displayName }
          : { id: version.reviewedBy, name: 'Unknown' },
        comment: version.reviewComment,
        timestamp: version.reviewedAt.toISOString(),
      });
    }

    return history;
  }

  // ============================================
  // 14. 获取我提交的审核 🆕
  // ============================================

  async findMySubmissions(query: QueryMySubmissionsDto, userId: string) {
    const { status, page = 1, limit = 20 } = query;

    const where: Prisma.FormVersionWhereInput = {
      createdBy: userId,
    };

    // 根据状态筛选
    if (status === ReviewSubmissionStatus.PENDING) {
      where.status = FormVersionStatus.PENDING_REVIEW;
    } else if (status === ReviewSubmissionStatus.APPROVED) {
      where.status = FormVersionStatus.PUBLISHED;
      where.reviewedBy = { not: null };
    } else if (status === ReviewSubmissionStatus.REJECTED) {
      where.status = FormVersionStatus.REJECTED;
    }

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

    return {
      items: items.map((item) => ({
        id: item.id,
        version: item.version,
        status: item.status,
        form: item.definition
          ? {
              id: item.definition.id,
              key: item.definition.key,
              slug: item.definition.slug,
              name: item.definition.name,
            }
          : null,
        submittedAt: item.createdAt.toISOString(),
        reviewedAt: item.reviewedAt?.toISOString() || null,
        reviewedBy: item.reviewer
          ? { id: item.reviewer.id, name: item.reviewer.displayName }
          : null,
        reviewComment: item.reviewComment,
      })),
      total,
      page,
      limit,
      totalPages: Math.ceil(total / limit),
    };
  }

  // ============================================
  // 15. 版本对比 🆕
  // ============================================

  async compareVersions(formIdentifier: string, fromVersion: number, toVersion: number) {
    const form = await this.identifierResolver.resolveFormDefinition(
      formIdentifier
    ) as any;

    const [from, to] = await Promise.all([
      this.prisma.formVersion.findFirst({
        where: { definitionId: form.id, version: fromVersion },
      }),
      this.prisma.formVersion.findFirst({
        where: { definitionId: form.id, version: toVersion },
      }),
    ]);

    if (!from) {
      throw new NotFoundException(`Version ${fromVersion} not found`);
    }
    if (!to) {
      throw new NotFoundException(`Version ${toVersion} not found`);
    }

    const diff = this.compareSchemas(from.schema as any, to.schema as any);

    return {
      fromVersion,
      toVersion,
      changes: diff,
      changelog: to.changelog,
    };
  }

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

  /**
   * 比较两个 Schema 的差异
   */
  private compareSchemas(
    oldSchema: any,
    newSchema: any
  ): {
    fieldsAdded: any[];
    fieldsRemoved: any[];
    fieldsModified: any[];
  } {
    const result = {
      fieldsAdded: [] as any[],
      fieldsRemoved: [] as any[],
      fieldsModified: [] as any[],
    };

    if (!oldSchema || !newSchema) {
      return result;
    }

    const oldFields = oldSchema.properties || {};
    const newFields = newSchema.properties || {};

    const oldFieldNames = Object.keys(oldFields);
    const newFieldNames = Object.keys(newFields);

    // 新增字段
    for (const name of newFieldNames) {
      if (!oldFieldNames.includes(name)) {
        result.fieldsAdded.push({
          name,
          ...newFields[name],
        });
      }
    }

    // 删除字段
    for (const name of oldFieldNames) {
      if (!newFieldNames.includes(name)) {
        result.fieldsRemoved.push({
          name,
          ...oldFields[name],
        });
      }
    }

    // 修改字段
    for (const name of newFieldNames) {
      if (oldFieldNames.includes(name)) {
        const oldField = JSON.stringify(oldFields[name]);
        const newField = JSON.stringify(newFields[name]);
        if (oldField !== newField) {
          result.fieldsModified.push({
            name,
            changes: {
              old: oldFields[name],
              new: newFields[name],
            },
          });
        }
      }
    }

    return result;
  }
}

