import { Injectable, Logger } from '@nestjs/common';

/**
 * 业务数据
 */
export interface BusinessData {
  id: string;
  title: string;
  data: any;
  metadata?: Record<string, any>;
}

/**
 * 业务摘要（用于列表显示）
 */
export interface BusinessSummary {
  title: string;
  description?: string;
  amount?: number;
  customFields?: Record<string, any>;
}

/**
 * 数据变更记录
 * 用于审批人修改数据后的同步和审计
 */
export interface DataChanges {
  [field: string]: {
    old: any;
    new: any;
  };
}

/**
 * 审批结果类型
 */
export type ApprovalResult = 'APPROVED' | 'REJECTED' | 'WITHDRAWN' | 'CANCELLED';

/**
 * 业务类型元数据
 * 
 * 设计原则（TD-6）：审批引擎与业务数据解耦
 * - 审批引擎不存储业务数据副本
 * - 通过此接口按需获取业务数据
 * - 数据变更通过回调同步到业务系统
 */
export interface BusinessTypeMetadata {
  type: string;                    // 业务类型标识，如 'FORM_INSTANCE'
  displayName: string;             // 显示名称，如 '表单申请'
  icon: string;                    // 图标名称
  color: string;                   // 主题色

  // ==================== 数据获取 ====================
  
  /**
   * 获取业务数据（用于详情页和条件评估）
   * 这是审批引擎获取业务数据的唯一入口
   */
  getBusinessData: (businessId: string) => Promise<BusinessData>;

  /**
   * 获取业务摘要（用于列表显示，轻量级）
   */
  getBusinessSummary: (businessId: string) => Promise<BusinessSummary>;

  // ==================== 数据同步 ====================
  
  /**
   * 同步审批人对数据的修改
   * 当审批人在审批过程中修改了可编辑字段时调用
   * 
   * @param businessId - 业务ID
   * @param changes - 变更记录 { field: { old, new } }
   * @param operatorId - 操作人ID
   */
  syncDataChanges?: (
    businessId: string,
    changes: DataChanges,
    operatorId: string,
  ) => Promise<void>;

  /**
   * 审批完成后更新业务状态
   * 
   * @param businessId - 业务ID
   * @param result - 审批结果
   * @param comment - 审批意见（可选）
   */
  onApprovalComplete?: (
    businessId: string,
    result: ApprovalResult,
    comment?: string,
  ) => Promise<void>;

  // ==================== 路由与展示 ====================
  
  /**
   * 前端详情页路由
   */
  detailRoute: (businessId: string, instanceId: string) => string;

  /**
   * 列表额外字段（可选）
   */
  listFields?: string[];
}

/**
 * 业务类型注册表
 * 
 * 用于管理不同业务类型的元数据和回调函数，支持扩展新的业务类型
 */
@Injectable()
export class BusinessTypeRegistry {
  private readonly logger = new Logger(BusinessTypeRegistry.name);
  private readonly registry = new Map<string, BusinessTypeMetadata>();

  /**
   * 注册业务类型
   */
  register(metadata: BusinessTypeMetadata): void {
    if (this.registry.has(metadata.type)) {
      this.logger.warn(`Business type ${metadata.type} already registered, overwriting`);
    }

    this.registry.set(metadata.type, metadata);
    this.logger.log(`Registered business type: ${metadata.type} (${metadata.displayName})`);
  }

  /**
   * 获取业务类型元数据
   */
  getMetadata(type: string): BusinessTypeMetadata | undefined {
    return this.registry.get(type);
  }

  /**
   * 获取所有已注册的业务类型
   */
  getAllTypes(): string[] {
    return Array.from(this.registry.keys());
  }

  /**
   * 获取所有业务类型的元数据
   */
  getAllMetadata(): BusinessTypeMetadata[] {
    return Array.from(this.registry.values());
  }

  /**
   * 批量获取业务摘要（用于列表显示）
   */
  async getBatchSummaries(
    items: Array<{ businessType: string; businessId: string }>,
  ): Promise<
    Array<{
      businessType: string;
      businessId: string;
      summary: BusinessSummary | null;
      metadata: Pick<BusinessTypeMetadata, 'displayName' | 'icon' | 'color'> | null;
      error?: string;
    }>
  > {
    const results = await Promise.all(
      items.map(async (item) => {
        let metadata = this.getMetadata(item.businessType);

        // Fallback: 如果找不到业务类型，尝试作为表单key处理（兼容旧数据）
        if (!metadata && item.businessType !== 'FORM_INSTANCE') {
          this.logger.warn(`Unknown business type: ${item.businessType}, trying FORM_INSTANCE fallback`);
          metadata = this.getMetadata('FORM_INSTANCE');
        }

        if (!metadata) {
          this.logger.warn(`Unknown business type: ${item.businessType}, no fallback available`);
          return {
            ...item,
            summary: null,
            metadata: null,
            error: 'Unknown business type',
          };
        }

        try {
          const summary = await metadata.getBusinessSummary(item.businessId);
          return {
            ...item,
            summary,
            metadata: {
              displayName: metadata.displayName,
              icon: metadata.icon,
              color: metadata.color,
            },
          };
        } catch (error) {
          this.logger.error(
            `Failed to get business summary for ${item.businessType}/${item.businessId}: ${error.message}`,
          );
          return {
            ...item,
            summary: null,
            metadata: {
              displayName: metadata.displayName,
              icon: metadata.icon,
              color: metadata.color,
            },
            error: error.message,
          };
        }
      }),
    );

    return results;
  }

  /**
   * 获取单个业务数据（用于详情页）
   */
  async getBusinessData(businessType: string, businessId: string): Promise<BusinessData | null> {
    const metadata = this.getMetadata(businessType);

    if (!metadata) {
      this.logger.warn(`Unknown business type: ${businessType}`);
      return null;
    }

    try {
      return await metadata.getBusinessData(businessId);
    } catch (error) {
      this.logger.error(
        `Failed to get business data for ${businessType}/${businessId}: ${error.message}`,
      );
      throw error;
    }
  }

  /**
   * 获取详情页路由
   */
  getDetailRoute(businessType: string, businessId: string, instanceId: string): string | null {
    const metadata = this.getMetadata(businessType);

    if (!metadata) {
      return null;
    }

    return metadata.detailRoute(businessId, instanceId);
  }

  // ==================== 数据同步方法（TD-6 实现） ====================

  /**
   * 同步审批人对数据的修改到业务系统
   * 
   * @param businessType - 业务类型
   * @param businessId - 业务ID
   * @param changes - 变更记录
   * @param operatorId - 操作人ID
   */
  async syncDataChanges(
    businessType: string,
    businessId: string,
    changes: DataChanges,
    operatorId: string,
  ): Promise<void> {
    const metadata = this.getMetadata(businessType);

    if (!metadata) {
      this.logger.warn(`Cannot sync data changes: unknown business type ${businessType}`);
      return;
    }

    if (!metadata.syncDataChanges) {
      this.logger.debug(`Business type ${businessType} does not support data sync`);
      return;
    }

    try {
      await metadata.syncDataChanges(businessId, changes, operatorId);
      this.logger.log(
        `Synced data changes for ${businessType}/${businessId}: ${Object.keys(changes).length} fields`,
      );
    } catch (error) {
      this.logger.error(
        `Failed to sync data changes for ${businessType}/${businessId}: ${error.message}`,
      );
      throw error;
    }
  }

  /**
   * 通知业务系统审批完成
   * 
   * @param businessType - 业务类型
   * @param businessId - 业务ID
   * @param result - 审批结果
   * @param comment - 审批意见
   */
  async notifyApprovalComplete(
    businessType: string,
    businessId: string,
    result: ApprovalResult,
    comment?: string,
  ): Promise<void> {
    const metadata = this.getMetadata(businessType);

    if (!metadata) {
      this.logger.warn(`Cannot notify approval complete: unknown business type ${businessType}`);
      return;
    }

    if (!metadata.onApprovalComplete) {
      this.logger.debug(`Business type ${businessType} does not handle approval complete`);
      return;
    }

    try {
      await metadata.onApprovalComplete(businessId, result, comment);
      this.logger.log(
        `Notified approval complete for ${businessType}/${businessId}: ${result}`,
      );
    } catch (error) {
      this.logger.error(
        `Failed to notify approval complete for ${businessType}/${businessId}: ${error.message}`,
      );
      throw error;
    }
  }

  /**
   * 获取用于条件评估的业务数据
   * 
   * 此方法专门用于审批引擎的条件分支评估
   * 返回的数据可以直接用于表达式计算
   * 
   * @param businessType - 业务类型
   * @param businessId - 业务ID
   * @returns 业务数据（扁平化的键值对，用于条件表达式）
   */
  async getBusinessDataForCondition(
    businessType: string,
    businessId: string,
  ): Promise<Record<string, any>> {
    const businessData = await this.getBusinessData(businessType, businessId);
    
    if (!businessData) {
      this.logger.warn(`No business data found for condition evaluation: ${businessType}/${businessId}`);
      return {};
    }

    // 返回 data 字段，这是业务数据的主体
    // 业务系统可以在 getBusinessData 中决定返回什么结构
    return businessData.data || {};
  }
}

