import { Injectable, Logger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { PrismaService } from '@core/database/prisma/prisma.service';
import { DingtalkYidaService } from '../sdk/dingtalk-yida.service';
import { SapPurchaseService, SapEnvironment } from '../sap/sap-purchase.service';
import { PurchaseFormData, buildSapHeader, buildSapItem } from '../sap/sap-field-mapping';
import { FORM_UUIDS, PURCHASE_REQUEST_FIELDS } from '../constants/form-fields';
import { SyncLogger } from './sync-logger';
import { SyncExecutionResult } from './business-trip-sync.service';
import { formatTimeDisplay, nowChinaTimeString } from '../utils';

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

  constructor(
    private yidaService: DingtalkYidaService,
    private sapService: SapPurchaseService,
    private prisma: PrismaService,
    private configService: ConfigService,
  ) {}

  private getPurchaseFormUuid(sapEnv: SapEnvironment): string {
    return sapEnv === 'production'
      ? FORM_UUIDS.PURCHASE_REQUEST_PROD
      : FORM_UUIDS.PURCHASE_REQUEST_TEST;
  }

  async sync(
    fromTime?: string,
    toTime?: string,
    userId?: string,
    externalLogger?: SyncLogger,
    sapEnv: SapEnvironment = 'production',
  ): Promise<SyncExecutionResult> {
    const logger = externalLogger || new SyncLogger('PurchaseSapSyncService');
    const startTime = Date.now();
    let processedCount = 0;
    const errors: string[] = [];

    const formUuid = this.getPurchaseFormUuid(sapEnv);
    const env = sapEnv;

    logger.log('----开始采购申请SAP同步----');
    const { displayFrom, displayTo } = formatTimeDisplay(fromTime, toTime);
    logger.log(`处理区间: ${displayFrom} ~ ${displayTo}`);
    logger.log(`SAP 环境: ${env}, 表单: ${formUuid}`);
    if (userId) logger.log(`指定员工: ${userId}`);

    try {
      // 1. 查询审批通过的采购申请
      const formData = await this.yidaService.searchApprovedInstances(
        formUuid,
        fromTime,
        toTime,
        userId,
      );
      logger.log(`从宜搭获取到 ${formData.length} 条审批通过的采购申请`);

      if (formData.length === 0) {
        logger.log('无待同步数据，跳过');
        return {
          success: true,
          processedCount: 0,
          errors: [],
          duration: Date.now() - startTime,
          logs: logger.getText(),
        };
      }

      // 2. 逐条处理
      for (const item of formData) {
        const fd = item.formData || {};
        const serialNumber = fd[PURCHASE_REQUEST_FIELDS.SERIAL_NUMBER] || '';
        const applicantName = fd[PURCHASE_REQUEST_FIELDS.APPLICANT_NAME] || '';
        const budgetAmount = parseFloat(fd[PURCHASE_REQUEST_FIELDS.BUDGET_AMOUNT]) || 0;
        const formInstanceId = item.formInstanceId || item.formInstId || '';

        if (!serialNumber) {
          logger.warn(`跳过无流水号的记录: formInstanceId=${formInstanceId}`);
          continue;
        }

        // 2a. 去重检查
        const existing = await this.prisma.sapPurchaseSyncRecord.findUnique({
          where: { serialNumber },
        });
        if (existing?.sapStatus === 'SUCCESS' || existing?.sapStatus === 'EXISTS') {
          logger.log(`跳过已成功同步: ${serialNumber} (PR号: ${existing.sapPrNumber})`);
          continue;
        }

        // 2b. 校验必填字段
        if (budgetAmount <= 0) {
          logger.warn(`跳过预算为0的记录: ${serialNumber}`);
          continue;
        }
        if (!applicantName) {
          logger.warn(`跳过无申请人的记录: ${serialNumber}`);
          continue;
        }

        logger.log(`处理采购申请: ${serialNumber} (${applicantName}, ¥${budgetAmount})`);

        try {
          // 2c. 获取 processInstanceId
          let processInstanceId = '';
          try {
            const instanceDetail = await this.yidaService.getInstanceById(formInstanceId);
            processInstanceId = instanceDetail?.processInstanceId || '';
          } catch (e: any) {
            logger.warn(`获取实例详情失败 (${formInstanceId}): ${e.message}`);
          }

          // 2d. 获取审批链
          let approverChain = '';
          if (processInstanceId) {
            try {
              const records = await this.yidaService.getOperationRecords(processInstanceId);
              approverChain = this.buildApproverChain(records);
              logger.log(`审批链: ${approverChain}`);
            } catch (e: any) {
              logger.warn(`获取审批链失败 (${processInstanceId}): ${e.message}`);
            }
          } else {
            logger.warn(`无 processInstanceId，跳过审批链提取`);
          }

          // 2e. 构建 PurchaseFormData
          const purchaseData = this.buildPurchaseFormData(fd, formInstanceId, processInstanceId, approverChain);

          // 2f. 调用 SAP
          const result = await this.sapService.createPurchaseRequisition(purchaseData, sapEnv);

          // 2g. 写入数据库
          await this.upsertSyncRecord(serialNumber, result, formInstanceId, applicantName, budgetAmount, approverChain);

          if (result.alreadyExists) {
            processedCount++;
            logger.log(`已存在: ${serialNumber} → PR号: ${result.prNumber}（已回写）`);
          } else if (result.success) {
            processedCount++;
            logger.log(`同步成功: ${serialNumber} → PR号: ${result.prNumber}`);
          } else {
            const errMsg = `同步失败: ${serialNumber} - ${result.messages.map(m => `[${m.type}]${m.message}`).join('; ')}`;
            logger.error(errMsg);
            errors.push(errMsg);
          }
        } catch (itemError: any) {
          const errMsg = `处理异常: ${serialNumber} - ${itemError.message}`;
          logger.error(errMsg);
          errors.push(errMsg);
        }
      }

      logger.log(`----采购申请SAP同步完成: 成功 ${processedCount} 条, 错误 ${errors.length} 条----`);
    } catch (error: any) {
      const errMsg = `采购同步整体异常: ${error.message}`;
      logger.error(errMsg);
      errors.push(errMsg);
    }

    return {
      success: errors.length === 0,
      processedCount,
      errors,
      duration: Date.now() - startTime,
      logs: logger.getText(),
    };
  }

  private static readonly SYNC_CONFIG_TASK_CODE_PREFIX = 'SAP_PURCHASE_CACHE';

  /**
   * 查询采购申请列表（从本地缓存 + 同步状态）
   */
  async listPurchases(sapEnv: SapEnvironment = 'production', keyword?: string, status?: string) {
    const where: any = { sapEnv };
    if (keyword) {
      where.OR = [
        { serialNumber: { contains: keyword, mode: 'insensitive' } },
        { applicantName: { contains: keyword, mode: 'insensitive' } },
        { budgetNumber: { contains: keyword, mode: 'insensitive' } },
      ];
    }

    const cacheItems = await this.prisma.sapPurchaseCache.findMany({
      where,
      orderBy: { updatedAt: 'desc' },
    });

    // 批量查同步记录
    const serialNumbers = cacheItems.map(i => i.serialNumber);
    const syncRecords = serialNumbers.length > 0
      ? await this.prisma.sapPurchaseSyncRecord.findMany({
          where: { serialNumber: { in: serialNumbers } },
        })
      : [];
    const syncMap = new Map(syncRecords.map(r => [r.serialNumber, r]));

    let items = cacheItems.map(item => {
      const record = syncMap.get(item.serialNumber);
      const fd = (item.formData as Record<string, any>) || {};
      return {
        formInstanceId: item.formInstanceId,
        serialNumber: item.serialNumber,
        applicantName: item.applicantName,
        applicantDept: item.applicantDept,
        applicantEmployeeId: fd[PURCHASE_REQUEST_FIELDS.APPLICANT_EMPLOYEE_ID] || '',
        budgetNumber: item.budgetNumber,
        budgetAmount: Number(item.budgetAmount),
        purchaseProjectDescription: item.purchaseProjectDescription,
        applicationDate: item.applicationDate,
        demandCategory: item.demandCategory,
        demandInitiator: this.extractEmployeeFieldName(fd[PURCHASE_REQUEST_FIELDS.DEMAND_INITIATOR]),
        companyName: fd[PURCHASE_REQUEST_FIELDS.COMPANY_NAME] || '',
        purchasingCompanyName: item.purchasingCompanyName,
        purchaser: this.extractEmployeeFieldName(fd[PURCHASE_REQUEST_FIELDS.PURCHASER]),
        expectedCompletionDate: this.parseYidaDate(fd[PURCHASE_REQUEST_FIELDS.EXPECTED_COMPLETION_DATE]),
        materialGroup: item.materialGroup,
        costCenterNumber: fd[PURCHASE_REQUEST_FIELDS.COST_CENTER_NUMBER] || '',
        fixedAssetsNumber: fd[PURCHASE_REQUEST_FIELDS.FIXED_ASSETS_NUMBER] || '',
        generalLedgerAccount: fd[PURCHASE_REQUEST_FIELDS.GENERAL_LEDGER_ACCOUNT] || '',
        // 同步状态
        syncStatus: record ? record.sapStatus as string : 'NOT_SYNCED',
        sapPrNumber: record?.sapPrNumber || null,
        sapMessages: record?.sapMessages || null,
        sapRawResponse: record?.sapRawResponse || null,
        approverChain: record?.approverChain || null,
        syncedAt: record?.syncedAt?.toISOString() || null,
        // SAP 请求预览（基于缓存数据动态构建）
        sapRequestPreview: (() => {
          try {
            const previewData: PurchaseFormData = {
              formInstanceId: item.formInstanceId,
              processInstanceId: '',
              serialNumber: item.serialNumber,
              applicantName: item.applicantName,
              applicantEmployeeId: fd[PURCHASE_REQUEST_FIELDS.APPLICANT_EMPLOYEE_ID] || '',
              applicantId: fd[PURCHASE_REQUEST_FIELDS.APPLICANT_ID] || '',
              applicantDept: item.applicantDept,
              applicationDate: item.applicationDate,
              companyName: fd[PURCHASE_REQUEST_FIELDS.COMPANY_NAME] || '',
              purchasingCompanyName: item.purchasingCompanyName,
              purchaser: this.extractEmployeeFieldName(fd[PURCHASE_REQUEST_FIELDS.PURCHASER]),
              expectedCompletionDate: this.parseYidaDate(fd[PURCHASE_REQUEST_FIELDS.EXPECTED_COMPLETION_DATE]),
              demandInitiator: this.extractEmployeeFieldName(fd[PURCHASE_REQUEST_FIELDS.DEMAND_INITIATOR]),
              demandCategory: item.demandCategory,
              budgetNumber: item.budgetNumber,
              budgetAmount: Number(item.budgetAmount),
              purchaseProjectDescription: item.purchaseProjectDescription,
              materialGroup: item.materialGroup,
              costCenterNumber: fd[PURCHASE_REQUEST_FIELDS.COST_CENTER_NUMBER] || '',
              fixedAssetsNumber: fd[PURCHASE_REQUEST_FIELDS.FIXED_ASSETS_NUMBER] || '',
              generalLedgerAccount: fd[PURCHASE_REQUEST_FIELDS.GENERAL_LEDGER_ACCOUNT] || '',
              approverChain: record?.approverChain || '',
            };
            return {
              header: buildSapHeader(previewData),
              item: buildSapItem(previewData),
            };
          } catch {
            return null;
          }
        })(),
      };
    });

    if (status && status !== 'ALL') {
      items = items.filter(i => i.syncStatus === status);
    }

    return { items, total: items.length };
  }

  /**
   * 从宜搭增量拉取采购申请到本地缓存
   */
  async refreshPurchaseCache(sapEnv: SapEnvironment = 'production') {
    const configKey = `${PurchaseSapSyncService.SYNC_CONFIG_TASK_CODE_PREFIX}_${sapEnv.toUpperCase()}`;
    const formUuid = this.getPurchaseFormUuid(sapEnv);

    // 读取上次同步水位
    const config = await this.prisma.dingtalkSyncConfig.findUnique({
      where: { taskCode: configKey },
    });
    const lastSyncToTime = (config?.metadata as any)?.lastSyncToTime || '2026-01-01 00:00:00';
    const toTime = nowChinaTimeString();

    // 从宜搭增量查询
    const formData = await this.yidaService.searchApprovedInstances(
      formUuid,
      lastSyncToTime,
      toTime,
    );

    let upsertCount = 0;
    for (const item of formData) {
      const fd = item.formData || {};
      const serialNumber = fd[PURCHASE_REQUEST_FIELDS.SERIAL_NUMBER] || '';
      if (!serialNumber) continue;

      await this.prisma.sapPurchaseCache.upsert({
        where: { serialNumber },
        create: {
          serialNumber,
          formInstanceId: item.formInstanceId || item.formInstId || '',
          sapEnv,
          applicantName: fd[PURCHASE_REQUEST_FIELDS.APPLICANT_NAME] || '',
          applicantDept: fd[PURCHASE_REQUEST_FIELDS.APPLICANT_DEPT] || '',
          budgetNumber: fd[PURCHASE_REQUEST_FIELDS.BUDGET_NUMBER] || '',
          budgetAmount: parseFloat(fd[PURCHASE_REQUEST_FIELDS.BUDGET_AMOUNT]) || 0,
          purchaseProjectDescription: fd[PURCHASE_REQUEST_FIELDS.PURCHASE_PROJECT_DESCRIPTION] || '',
          applicationDate: this.parseYidaDate(fd[PURCHASE_REQUEST_FIELDS.APPLICATION_DATE]),
          demandCategory: fd[PURCHASE_REQUEST_FIELDS.DEMAND_CATEGORY] || '',
          purchasingCompanyName: fd[PURCHASE_REQUEST_FIELDS.PURCHASING_COMPANY_NAME] || '',
          materialGroup: fd[PURCHASE_REQUEST_FIELDS.MATERIAL_GROUP] || '',
          formData: fd,
          yidaModifiedAt: item.modifiedTimeGMT || '',
        },
        update: {
          formInstanceId: item.formInstanceId || item.formInstId || '',
          applicantName: fd[PURCHASE_REQUEST_FIELDS.APPLICANT_NAME] || '',
          applicantDept: fd[PURCHASE_REQUEST_FIELDS.APPLICANT_DEPT] || '',
          budgetNumber: fd[PURCHASE_REQUEST_FIELDS.BUDGET_NUMBER] || '',
          budgetAmount: parseFloat(fd[PURCHASE_REQUEST_FIELDS.BUDGET_AMOUNT]) || 0,
          purchaseProjectDescription: fd[PURCHASE_REQUEST_FIELDS.PURCHASE_PROJECT_DESCRIPTION] || '',
          applicationDate: this.parseYidaDate(fd[PURCHASE_REQUEST_FIELDS.APPLICATION_DATE]),
          demandCategory: fd[PURCHASE_REQUEST_FIELDS.DEMAND_CATEGORY] || '',
          purchasingCompanyName: fd[PURCHASE_REQUEST_FIELDS.PURCHASING_COMPANY_NAME] || '',
          materialGroup: fd[PURCHASE_REQUEST_FIELDS.MATERIAL_GROUP] || '',
          formData: fd,
          yidaModifiedAt: item.modifiedTimeGMT || '',
        },
      });
      upsertCount++;
    }

    // 更新同步水位
    await this.prisma.dingtalkSyncConfig.upsert({
      where: { taskCode: configKey },
      create: {
        taskCode: configKey,
        syncDirection: 'YIDA_TO_LOCAL',
        metadata: { lastSyncToTime: toTime },
      },
      update: {
        metadata: { lastSyncToTime: toTime },
      },
    });

    return {
      fetched: formData.length,
      upserted: upsertCount,
      fromTime: lastSyncToTime || '(首次全量)',
      toTime,
    };
  }

  /**
   * 查询同步记录（分页）
   */
  async getRecords(page = 1, limit = 20, status?: string) {
    const where = status ? { sapStatus: status } : {};
    const [items, total] = await Promise.all([
      this.prisma.sapPurchaseSyncRecord.findMany({
        where,
        orderBy: { syncedAt: 'desc' },
        skip: (page - 1) * limit,
        take: limit,
      }),
      this.prisma.sapPurchaseSyncRecord.count({ where }),
    ]);
    return { items, total, page, limit, totalPages: Math.ceil(total / limit) };
  }

  /**
   * 同步指定采购单到 SAP（单条，供前端页面调用）
   * formData 从本地缓存读取
   */
  async syncSingle(
    serialNumber: string,
    sapEnv: SapEnvironment,
  ) {
    // 从缓存读取表单数据
    const cached = await this.prisma.sapPurchaseCache.findUnique({
      where: { serialNumber },
    });
    if (!cached) {
      throw new Error(`缓存中未找到采购申请: ${serialNumber}`);
    }
    const fd = (cached.formData as Record<string, any>) || {};
    const formInstanceId = cached.formInstanceId;
    const applicantName = cached.applicantName;
    const budgetAmount = Number(cached.budgetAmount);

    // 获取审批链
    let processInstanceId = '';
    let approverChain = '';
    try {
      const instanceDetail = await this.yidaService.getInstanceById(formInstanceId);
      // 宜搭 API 可能返回蛇形或驼峰命名
      processInstanceId = instanceDetail?.processInstanceId
        || instanceDetail?.process_instance_id
        || formInstanceId; // 宜搭中 formInstanceId 通常与 processInstanceId 相同
    } catch (e: any) {
      this.logger.warn(`获取实例详情失败 (${formInstanceId}), 回退使用 formInstanceId: ${e.message}`);
      processInstanceId = formInstanceId;
    }

    if (processInstanceId) {
      try {
        const records = await this.yidaService.getOperationRecords(processInstanceId);
        approverChain = this.buildApproverChain(records);
      } catch (e: any) {
        this.logger.warn(`获取审批链失败 (${processInstanceId}): ${e.message}`);
      }
    }

    const purchaseData = this.buildPurchaseFormData(fd, formInstanceId, processInstanceId, approverChain);

    const result = await this.sapService.createPurchaseRequisition(purchaseData, sapEnv);

    await this.upsertSyncRecord(serialNumber, result, formInstanceId, applicantName, budgetAmount, approverChain);

    return {
      serialNumber,
      success: result.success,
      alreadyExists: result.alreadyExists,
      prNumber: result.prNumber,
      messages: result.messages,
      approverChain,
    };
  }

  /**
   * 批量同步（供前端批量操作调用）
   */
  async syncBatch(
    serialNumbers: string[],
    sapEnv: SapEnvironment,
  ) {
    const results = [];
    for (const serialNumber of serialNumbers) {
      try {
        const result = await this.syncSingle(serialNumber, sapEnv);
        results.push(result);
      } catch (e: any) {
        results.push({
          serialNumber,
          success: false,
          prNumber: null,
          messages: [{ type: 'E', message: e.message }],
          approverChain: '',
        });
      }
    }
    return results;
  }

  private async upsertSyncRecord(
    serialNumber: string,
    result: import('../sap/sap-field-mapping').SapSyncResult,
    formInstanceId: string,
    applicantName: string,
    budgetAmount: number,
    approverChain: string,
  ) {
    const sapStatus = result.alreadyExists ? 'EXISTS' : result.success ? 'SUCCESS' : 'FAILED';
    await this.prisma.sapPurchaseSyncRecord.upsert({
      where: { serialNumber },
      create: {
        serialNumber, formInstanceId, applicantName, budgetAmount,
        sapPrNumber: result.prNumber, sapStatus,
        sapMessages: result.messages as any, sapRawResponse: result.rawResponse as any,
        approverChain,
      },
      update: {
        sapPrNumber: result.prNumber, sapStatus,
        sapMessages: result.messages as any, sapRawResponse: result.rawResponse as any,
        approverChain,
        syncedAt: new Date(),
      },
    });
  }

  private buildPurchaseFormData(
    fd: Record<string, any>,
    formInstanceId: string,
    processInstanceId: string,
    approverChain: string,
  ): PurchaseFormData {
    return {
      formInstanceId,
      processInstanceId,
      serialNumber: fd[PURCHASE_REQUEST_FIELDS.SERIAL_NUMBER] || '',
      applicantName: fd[PURCHASE_REQUEST_FIELDS.APPLICANT_NAME] || '',
      applicantEmployeeId: fd[PURCHASE_REQUEST_FIELDS.APPLICANT_EMPLOYEE_ID] || '',
      applicantId: fd[PURCHASE_REQUEST_FIELDS.APPLICANT_ID] || '',
      applicantDept: fd[PURCHASE_REQUEST_FIELDS.APPLICANT_DEPT] || '',
      applicationDate: this.parseYidaDate(fd[PURCHASE_REQUEST_FIELDS.APPLICATION_DATE]),
      companyName: fd[PURCHASE_REQUEST_FIELDS.COMPANY_NAME] || '',
      purchasingCompanyName: fd[PURCHASE_REQUEST_FIELDS.PURCHASING_COMPANY_NAME] || '',
      purchaser: this.extractEmployeeFieldName(fd[PURCHASE_REQUEST_FIELDS.PURCHASER]),
      expectedCompletionDate: this.parseYidaDate(fd[PURCHASE_REQUEST_FIELDS.EXPECTED_COMPLETION_DATE]),
      demandInitiator: this.extractEmployeeFieldName(fd[PURCHASE_REQUEST_FIELDS.DEMAND_INITIATOR]),
      demandCategory: fd[PURCHASE_REQUEST_FIELDS.DEMAND_CATEGORY] || '',
      budgetNumber: fd[PURCHASE_REQUEST_FIELDS.BUDGET_NUMBER] || '',
      budgetAmount: parseFloat(fd[PURCHASE_REQUEST_FIELDS.BUDGET_AMOUNT]) || 0,
      purchaseProjectDescription: fd[PURCHASE_REQUEST_FIELDS.PURCHASE_PROJECT_DESCRIPTION] || '',
      materialGroup: fd[PURCHASE_REQUEST_FIELDS.MATERIAL_GROUP] || '',
      costCenterNumber: fd[PURCHASE_REQUEST_FIELDS.COST_CENTER_NUMBER] || '',
      fixedAssetsNumber: fd[PURCHASE_REQUEST_FIELDS.FIXED_ASSETS_NUMBER] || '',
      generalLedgerAccount: fd[PURCHASE_REQUEST_FIELDS.GENERAL_LEDGER_ACCOUNT] || '',
      approverChain,
    };
  }

  /**
   * 从操作记录构建审批链
   * 移植自 Python: purchase_handler.py _extract_approvers + update_approver_chain
   */
  private buildApproverChain(records: any[]): string {
    if (!records || records.length === 0) return '';

    const seen = new Set<string>();
    const names: string[] = [];

    for (const record of records) {
      const name =
        record.operatorDisplayName ||
        record.operatorName ||
        record.operatorNickName ||
        '';
      if (name && !seen.has(name)) {
        seen.add(name);
        names.push(name);
      }
    }

    return names.length > 0 ? `[${names.join(' -> ')}]` : '';
  }

  /**
   * 解析宜搭日期字段（毫秒时间戳 → YYYY-MM-DD）
   */
  private parseYidaDate(value: any): string {
    if (!value) return '';
    if (typeof value === 'string') {
      if (value.length === 10 && value[4] === '-') return value;
      return value.split(' ')[0] || value;
    }
    if (typeof value === 'number') {
      const d = new Date(value);
      return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
    }
    return '';
  }

  /**
   * 提取宜搭员工字段的姓名
   * 员工字段通常是数组 [{name, ...}] 或字符串
   */
  private extractEmployeeFieldName(value: any): string {
    if (!value) return '';
    if (typeof value === 'string') return value;
    if (Array.isArray(value) && value.length > 0) {
      return value[0].name || value[0].label || '';
    }
    return '';
  }
}
