import { Injectable } from '@nestjs/common';
import { DingtalkYidaService } from '../sdk/dingtalk-yida.service';
import { DingtalkAttendanceService } from '../sdk/dingtalk-attendance.service';
import { DingtalkAuthService } from '../sdk/dingtalk-auth.service';
import { FORM_UUIDS, OVERTIME_FIELDS } from '../constants';
import { SyncExecutionResult } from './business-trip-sync.service';
import { SyncLogger } from './sync-logger';
import { getDingtalkSerialNumber, formatTimeDisplay } from '../utils';

@Injectable()
export class OvertimeSyncService {

  constructor(
    private yidaService: DingtalkYidaService,
    private attendanceService: DingtalkAttendanceService,
    private authService: DingtalkAuthService,
  ) {}

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

    logger.log('----开始加班考勤同步----');
    const { displayFrom, displayTo } = formatTimeDisplay(fromTime, toTime);
    logger.log(`处理区间: ${displayFrom} ~ ${displayTo}`);
    if (userId) logger.log(`指定员工: ${userId}`);

    const syncedRecords: { userId: string; name: string; fromDate: string; toDate: string; approveId: string }[] = [];

    try {
      const formData = await this.yidaService.searchApprovedInstances(
        FORM_UUIDS.OVERTIME_APPLICATION,
        fromTime,
        toTime,
        userId,
      );
      logger.log(`从宜搭获取到 ${formData.length} 条审批通过的加班申请${userId ? `（已按员工 ${userId} 过滤）` : ''}`);

      for (const data of formData) {
        const pageData = data.formData;
        const creatorId = data.creatorUserId;
        const instanceId = data.formInstanceId;
        const serialNumber = getDingtalkSerialNumber(data);
        const creator = pageData[OVERTIME_FIELDS.CREATOR];
        const allOvertimeTime = pageData[OVERTIME_FIELDS.TABLE_FIELD] || [];

        if (!serialNumber) {
          errors.push(`加班同步缺少流水号: ${creator || creatorId} instanceId=${instanceId}`);
          logger.error(`加班申请缺少 serial number，跳过: ${creator || creatorId} instanceId=${instanceId}`);
          continue;
        }

        let index = 1;
        for (const timeData of allOvertimeTime) {
          const approveId = `${serialNumber}-${index}`;
          const fromDate = this.formatDateTime(timeData[OVERTIME_FIELDS.FROM_DATE]);
          const toDate = this.formatDateTime(timeData[OVERTIME_FIELDS.TO_DATE]);
          const overtimeDuration = timeData[OVERTIME_FIELDS.DURATION];

          const jumpUrl = `https://s1k3ix.aliwork.com/${this.authService.appType}/processDetail?formInstId=${instanceId}`;

          try {
            const resp = await this.attendanceService.approveFinish({
              userId: creatorId,
              bizType: 1,
              fromDate,
              toDate,
              durationUnit: 'hour',
              calculateModel: 0,
              tagName: '加班',
              approveId,
              jumpUrl,
              overtimeDuration,
              overtimeToMore: 1,
            });

            if (resp.errcode === 0) {
              logger.log(`加班数据更新成功: ${creator} & ${creatorId} & ${fromDate} & ${toDate} & ${approveId}`);
              syncedRecords.push({ userId: creatorId, name: creator, fromDate, toDate, approveId });
              count++;
            }
          } catch (error: any) {
            errors.push(`加班同步失败 ${creator}: ${error.message}`);
            logger.error(`加班数据更新出错: ${error.message}`);
          }
          index++;
        }
      }
    } catch (error: any) {
      errors.push(`加班同步整体失败: ${error.message}`);
    }

    logger.log(`----加班考勤同步完成，共${count}条----`);

    // 同步后验证考勤状态
    if (syncedRecords.length > 0) {
      await this.verifyAttendanceStatus(syncedRecords, logger);
    }

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

  private async verifyAttendanceStatus(
    records: { userId: string; name: string; fromDate: string; toDate: string; approveId: string }[],
    logger: SyncLogger,
  ): Promise<void> {
    logger.log('----开始验证考勤状态----');

    const userDateMap = new Map<string, { name: string; dates: Set<string> }>();
    for (const r of records) {
      if (!userDateMap.has(r.userId)) {
        userDateMap.set(r.userId, { name: r.name, dates: new Set() });
      }
      userDateMap.get(r.userId)!.dates.add(r.fromDate.slice(0, 10));
    }

    let verifyOk = 0;
    let verifyFail = 0;

    for (const [uid, { name, dates }] of userDateMap) {
      const checkDates = [...dates].slice(0, 3);
      for (const date of checkDates) {
        try {
          const resp = await this.attendanceService.getApproveRecords(uid, date);
          if (resp.errcode !== 0) {
            logger.error(`验证失败: ${name}(${uid}) ${date} API错误 errcode=${resp.errcode}`);
            verifyFail++;
            continue;
          }

          const approveList = resp.result?.approve_list || [];
          const otRecords = approveList.filter((a: any) => a.tag_name === '加班');

          if (otRecords.length === 0) {
            logger.error(`验证异常: ${name}(${uid}) ${date} 无加班记录！`);
            verifyFail++;
          } else {
            logger.log(`验证通过: ${name}(${uid}) ${date} 加班✓ 共${otRecords.length}条`);
            verifyOk++;
          }
        } catch (error: any) {
          logger.error(`验证异常: ${name}(${uid}) ${date} ${error.message}`);
          verifyFail++;
        }
      }
    }

    logger.log(`----验证完成: ${verifyOk} 通过, ${verifyFail} 异常----`);
  }

  private formatDateTime(timestamp: number): string {
    // 宜搭时间戳为北京时间，需用 Asia/Shanghai 时区格式化
    const date = new Date(timestamp);
    const parts = new Intl.DateTimeFormat('sv-SE', {
      timeZone: 'Asia/Shanghai',
      year: 'numeric', month: '2-digit', day: '2-digit',
      hour: '2-digit', minute: '2-digit', hour12: false,
    }).formatToParts(date);
    const get = (type: string) => parts.find(p => p.type === type)?.value || '';
    return `${get('year')}-${get('month')}-${get('day')} ${get('hour')}:${get('minute')}`;
  }
}
