/**
 * 版本差异对比服务
 * 
 * 比较表单版本和流程版本之间的差异
 */

import { Injectable, Logger } from '@nestjs/common';
import { PrismaService } from '@core/database/prisma/prisma.service';
import {
  VersionDiffResponse,
  FieldChange,
  NodeChange,
  EdgeChange,
  ChangeType,
  VersionDiffQueryDto,
} from '../dto/query.dto';
import {
  FormNotFoundException,
  VersionNotFoundException,
  InvalidVersionRangeException,
} from '../exceptions';
import { RegionId } from '../decorators/region.decorator';
import { safeFindUnique } from '../utils/prisma-error-handler';

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

  constructor(private readonly prisma: PrismaService) {}

  /**
   * 对比两个版本的差异
   */
  async compareVersions(
    formId: string,
    query: VersionDiffQueryDto,
    regionId: RegionId,
  ): Promise<VersionDiffResponse> {
    const { from, to } = query;

    // 验证版本范围
    if (from >= to) {
      throw new InvalidVersionRangeException(from, to);
    }

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

    if (!form) {
      throw new FormNotFoundException(formId, regionId);
    }

    // 验证区域访问
    this.validateRegionAccess(form, regionId);

    // 获取两个版本
    const [fromVersion, toVersion] = await Promise.all([
      this.prisma.formVersion.findUnique({
        where: {
          definitionId_version: {
            definitionId: formId,
            version: from,
          },
        },
      }),
      this.prisma.formVersion.findUnique({
        where: {
          definitionId_version: {
            definitionId: formId,
            version: to,
          },
        },
      }),
    ]);

    if (!fromVersion) {
      throw new VersionNotFoundException(from, formId);
    }
    if (!toVersion) {
      throw new VersionNotFoundException(to, formId);
    }

    // 获取流程版本（如果有）
    let fromProcessVersion = null;
    let toProcessVersion = null;

    if (form.approvalProcessKey) {
      const processDef = await this.prisma.approvalDefinition.findUnique({
        where: { key: form.approvalProcessKey },
      });

      if (processDef) {
        [fromProcessVersion, toProcessVersion] = await Promise.all([
          this.prisma.approvalVersion.findFirst({
            where: {
              definitionId: processDef.id,
              version: from,
            },
          }),
          this.prisma.approvalVersion.findFirst({
            where: {
              definitionId: processDef.id,
              version: to,
            },
          }),
        ]);
      }
    }

    // 对比 Schema
    const schemaDiff = this.compareSchemas(
      fromVersion.schema as any,
      toVersion.schema as any,
    );

    // 对比 UI Schema
    const uiSchemaDiff = this.compareUiSchemas(
      fromVersion.uiSchema as any,
      toVersion.uiSchema as any,
    );

    // 对比流程
    const processDiff = this.compareProcessModels(
      fromProcessVersion?.processModel as any,
      toProcessVersion?.processModel as any,
    );

    return {
      from: {
        version: fromVersion.version,
        versionName: fromVersion.changelog || undefined,
        createdAt: fromVersion.createdAt.toISOString(),
      },
      to: {
        version: toVersion.version,
        versionName: toVersion.changelog || undefined,
        createdAt: toVersion.createdAt.toISOString(),
      },
      schema: schemaDiff,
      uiSchema: uiSchemaDiff,
      process: processDiff,
    };
  }

  /**
   * 对比两个快照的差异
   */
  async compareSnapshots(
    snapshotId1: string,
    snapshotId2: string,
    regionId: RegionId,
  ): Promise<VersionDiffResponse> {
    // 从快照 ID 提取版本 ID（模拟）
    const versionId1 = snapshotId1.replace('snap_', '');
    const versionId2 = snapshotId2.replace('snap_', '');

    const [version1, version2] = await Promise.all([
      this.prisma.formVersion.findUnique({
        where: { id: versionId1 },
        include: {
          definition: {
            include: {
              organization: {
                include: {
                  organizationRegions: {
                    include: { region: true }, // v2.0: 修复为 organizationRegions
                  },
                },
              },
            },
          },
        },
      }),
      this.prisma.formVersion.findUnique({
        where: { id: versionId2 },
        include: {
          definition: {
            include: {
              organization: {
                include: {
                  organizationRegions: {
                    include: { region: true }, // v2.0: 修复为 organizationRegions
                  },
                },
              },
            },
          },
        },
      }),
    ]);

    if (!version1) {
      throw new VersionNotFoundException(0, snapshotId1);
    }
    if (!version2) {
      throw new VersionNotFoundException(0, snapshotId2);
    }

    // 验证区域访问
    this.validateRegionAccess(version1.definition, regionId);
    this.validateRegionAccess(version2.definition, regionId);

    // 确保是同一个表单的版本
    if (version1.definitionId !== version2.definitionId) {
      throw new InvalidVersionRangeException(version1.version, version2.version);
    }

    // 获取流程版本
    let processVersion1 = null;
    let processVersion2 = null;

    if (version1.definition.approvalProcessKey) {
      const processDef = await this.prisma.approvalDefinition.findUnique({
        where: { key: version1.definition.approvalProcessKey },
      });

      if (processDef) {
        [processVersion1, processVersion2] = await Promise.all([
          this.prisma.approvalVersion.findFirst({
            where: {
              definitionId: processDef.id,
              version: version1.version,
            },
          }),
          this.prisma.approvalVersion.findFirst({
            where: {
              definitionId: processDef.id,
              version: version2.version,
            },
          }),
        ]);
      }
    }

    // 对比
    const schemaDiff = this.compareSchemas(
      version1.schema as any,
      version2.schema as any,
    );
    const uiSchemaDiff = this.compareUiSchemas(
      version1.uiSchema as any,
      version2.uiSchema as any,
    );
    const processDiff = this.compareProcessModels(
      processVersion1?.processModel as any,
      processVersion2?.processModel as any,
    );

    return {
      from: {
        version: version1.version,
        versionName: version1.changelog || undefined,
        createdAt: version1.createdAt.toISOString(),
      },
      to: {
        version: version2.version,
        versionName: version2.changelog || undefined,
        createdAt: version2.createdAt.toISOString(),
      },
      schema: schemaDiff,
      uiSchema: uiSchemaDiff,
      process: processDiff,
    };
  }

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

  private validateRegionAccess(form: any, regionId: RegionId) {
    // 平台级表单：所有区域可访问
    if (!form.organizationId) {
      return;
    }
    
    // 组织专属表单：检查组织是否在当前区域运营
    if (form.organization && form.organization.organizationRegions) {
      // v2.0: 使用 organizationRegions
      const orgRegionCodes = form.organization.organizationRegions
        .map((r: any) => r.region?.code)
        .filter(Boolean);
      
      if (!orgRegionCodes.includes(regionId)) {
        this.logger.warn(`[validateRegionAccess] 表单 ${form.id} 的组织区域 [${orgRegionCodes.join(', ')}] 不包含用户区域 ${regionId}`);
        throw new FormNotFoundException(form.id, regionId);
      }
      
      this.logger.debug(`[validateRegionAccess] 表单 ${form.id} 区域校验通过: ${regionId} in [${orgRegionCodes.join(', ')}]`);
    }
  }

  /**
   * 对比两个 JSON Schema
   */
  private compareSchemas(
    oldSchema: any,
    newSchema: any,
  ): { added: FieldChange[]; removed: FieldChange[]; modified: FieldChange[] } {
    const added: FieldChange[] = [];
    const removed: FieldChange[] = [];
    const modified: FieldChange[] = [];

    const oldProps = oldSchema?.properties || {};
    const newProps = newSchema?.properties || {};

    const allKeys = new Set([...Object.keys(oldProps), ...Object.keys(newProps)]);

    for (const key of allKeys) {
      const oldProp = oldProps[key];
      const newProp = newProps[key];
      const path = `$.properties.${key}`;

      if (!oldProp && newProp) {
        // 新增字段
        added.push({
          fieldKey: key,
          attribute: 'field',
          changeType: ChangeType.ADDED,
          newValue: newProp,
          path,
        });
      } else if (oldProp && !newProp) {
        // 删除字段
        removed.push({
          fieldKey: key,
          attribute: 'field',
          changeType: ChangeType.REMOVED,
          oldValue: oldProp,
          path,
        });
      } else if (oldProp && newProp) {
        // 检查字段属性变化
        const changes = this.compareFieldProperties(key, oldProp, newProp, path);
        modified.push(...changes);
      }
    }

    // 检查 required 数组变化
    const oldRequired = new Set<string>(oldSchema?.required || []);
    const newRequired = new Set<string>(newSchema?.required || []);

    for (const field of newRequired) {
      if (!oldRequired.has(field)) {
        modified.push({
          fieldKey: field,
          attribute: 'required',
          changeType: ChangeType.MODIFIED,
          oldValue: false,
          newValue: true,
          path: `$.required`,
        });
      }
    }

    for (const field of oldRequired) {
      if (!newRequired.has(field)) {
        modified.push({
          fieldKey: field,
          attribute: 'required',
          changeType: ChangeType.MODIFIED,
          oldValue: true,
          newValue: false,
          path: `$.required`,
        });
      }
    }

    return { added, removed, modified };
  }

  /**
   * 对比字段属性
   */
  private compareFieldProperties(
    fieldKey: string,
    oldProp: any,
    newProp: any,
    basePath: string,
  ): FieldChange[] {
    const changes: FieldChange[] = [];
    const attributes = ['type', 'title', 'description', 'default', 'enum', 'minimum', 'maximum'];

    for (const attr of attributes) {
      const oldValue = oldProp[attr];
      const newValue = newProp[attr];

      if (JSON.stringify(oldValue) !== JSON.stringify(newValue)) {
        changes.push({
          fieldKey,
          attribute: attr,
          changeType: ChangeType.MODIFIED,
          oldValue,
          newValue,
          path: `${basePath}.${attr}`,
        });
      }
    }

    return changes;
  }

  /**
   * 对比 UI Schema
   */
  private compareUiSchemas(
    oldUiSchema: any,
    newUiSchema: any,
  ): { added: any[]; removed: any[]; modified: any[] } {
    const added: any[] = [];
    const removed: any[] = [];
    const modified: any[] = [];

    if (!oldUiSchema && !newUiSchema) {
      return { added, removed, modified };
    }

    const oldOrder = oldUiSchema?.['ui:order'] || [];
    const newOrder = newUiSchema?.['ui:order'] || [];

    if (JSON.stringify(oldOrder) !== JSON.stringify(newOrder)) {
      modified.push({
        attribute: 'ui:order',
        oldValue: oldOrder,
        newValue: newOrder,
        path: '$["ui:order"]',
      });
    }

    // 对比每个字段的 UI 配置
    const allKeys = new Set([
      ...Object.keys(oldUiSchema || {}),
      ...Object.keys(newUiSchema || {}),
    ]);

    for (const key of allKeys) {
      if (key === 'ui:order') continue;

      const oldConfig = oldUiSchema?.[key];
      const newConfig = newUiSchema?.[key];

      if (!oldConfig && newConfig) {
        added.push({ field: key, config: newConfig });
      } else if (oldConfig && !newConfig) {
        removed.push({ field: key, config: oldConfig });
      } else if (JSON.stringify(oldConfig) !== JSON.stringify(newConfig)) {
        modified.push({
          field: key,
          oldConfig,
          newConfig,
        });
      }
    }

    return { added, removed, modified };
  }

  /**
   * 对比流程模型
   */
  private compareProcessModels(
    oldModel: any,
    newModel: any,
  ): {
    nodes: { added: NodeChange[]; removed: NodeChange[]; modified: NodeChange[] };
    edges: { added: EdgeChange[]; removed: EdgeChange[]; modified: EdgeChange[] };
  } {
    const nodesResult = this.compareNodes(
      oldModel?.nodes || [],
      newModel?.nodes || [],
    );
    const edgesResult = this.compareEdges(
      oldModel?.edges || [],
      newModel?.edges || [],
    );

    return {
      nodes: nodesResult,
      edges: edgesResult,
    };
  }

  /**
   * 对比节点
   */
  private compareNodes(
    oldNodes: any[],
    newNodes: any[],
  ): { added: NodeChange[]; removed: NodeChange[]; modified: NodeChange[] } {
    const added: NodeChange[] = [];
    const removed: NodeChange[] = [];
    const modified: NodeChange[] = [];

    const oldNodesMap = new Map(oldNodes.map((n) => [n.id, n]));
    const newNodesMap = new Map(newNodes.map((n) => [n.id, n]));

    // 查找新增和修改的节点
    for (const [id, newNode] of newNodesMap) {
      const oldNode = oldNodesMap.get(id);
      if (!oldNode) {
        added.push({
          nodeId: id,
          changeType: ChangeType.ADDED,
          newValue: newNode,
        });
      } else if (JSON.stringify(oldNode) !== JSON.stringify(newNode)) {
        modified.push({
          nodeId: id,
          changeType: ChangeType.MODIFIED,
          oldValue: oldNode,
          newValue: newNode,
        });
      }
    }

    // 查找删除的节点
    for (const [id, oldNode] of oldNodesMap) {
      if (!newNodesMap.has(id)) {
        removed.push({
          nodeId: id,
          changeType: ChangeType.REMOVED,
          oldValue: oldNode,
        });
      }
    }

    return { added, removed, modified };
  }

  /**
   * 对比边
   */
  private compareEdges(
    oldEdges: any[],
    newEdges: any[],
  ): { added: EdgeChange[]; removed: EdgeChange[]; modified: EdgeChange[] } {
    const added: EdgeChange[] = [];
    const removed: EdgeChange[] = [];
    const modified: EdgeChange[] = [];

    const getEdgeKey = (e: any) => `${e.source}->${e.target}`;
    const oldEdgesMap = new Map(oldEdges.map((e) => [getEdgeKey(e), e]));
    const newEdgesMap = new Map(newEdges.map((e) => [getEdgeKey(e), e]));

    // 查找新增和修改的边
    for (const [key, newEdge] of newEdgesMap) {
      const oldEdge = oldEdgesMap.get(key);
      if (!oldEdge) {
        added.push({
          source: newEdge.source,
          target: newEdge.target,
          changeType: ChangeType.ADDED,
          newValue: newEdge,
        });
      } else if (JSON.stringify(oldEdge) !== JSON.stringify(newEdge)) {
        modified.push({
          source: newEdge.source,
          target: newEdge.target,
          changeType: ChangeType.MODIFIED,
          oldValue: oldEdge,
          newValue: newEdge,
        });
      }
    }

    // 查找删除的边
    for (const [key, oldEdge] of oldEdgesMap) {
      if (!newEdgesMap.has(key)) {
        removed.push({
          source: oldEdge.source,
          target: oldEdge.target,
          changeType: ChangeType.REMOVED,
          oldValue: oldEdge,
        });
      }
    }

    return { added, removed, modified };
  }
}
