import { ServiceUnavailableException } from '@nestjs/common';
import type {
  DingTalkServiceContext,
  DingTalkShiftParams,
  DingTalkShiftSummary,
} from './dingtalk.types';

export class DingTalkShiftClient {
  constructor(private readonly context: DingTalkServiceContext) {}

  /** 创建或修改班次。id 不传=创建，传了=修改 */
  async upsertShift(params: DingTalkShiftParams): Promise<number> {
    if (!(await this.context.isConfigured())) throw new ServiceUnavailableException('钉钉未配置');
    const token = await this.context.getAccessToken();

    const body: Record<string, unknown> = {
      op_user_id: params.owner || 'manager',
      shift: {
        name: params.name,
        owner: params.owner,
        sections: params.sections.map((s) => ({
          times: s.times.map((t) => ({
            check_type: t.check_type,
            across: t.across,
            check_time: t.check_time,
            begin_min: t.begin_min ?? -1,
            end_min: t.end_min ?? -1,
            free_check: t.free_check ?? false,
          })),
        })),
        setting: params.setting
          ? {
              is_flexible: params.setting.is_flexible ?? false,
              serious_late_minutes: params.setting.serious_late_minutes ?? -1,
              absenteeism_late_minutes: params.setting.absenteeism_late_minutes ?? -1,
            }
          : undefined,
      },
    };
    if (params.id) (body.shift as Record<string, unknown>).id = params.id;

    await this.context.rateLimit();
    const res = await fetch(
      `https://oapi.dingtalk.com/topapi/attendance/shift/add?access_token=${token}`,
      {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(body),
      },
    );
    const data = (await res.json()) as {
      errcode: number; errmsg: string;
      result?: { id: number; name: string };
    };
    if (data.errcode !== 0) {
      throw new Error(`钉钉班次操作失败: ${data.errmsg} (code=${data.errcode})`);
    }
    this.context.logger.log(`钉钉班次 ${params.id ? '更新' : '创建'} 成功: ${data.result?.name} (id=${data.result?.id})`);
    return data.result!.id;
  }

  /** 查询所有班次摘要（每页最多200条） */
  async queryShifts(opUserId = 'manager'): Promise<DingTalkShiftSummary[]> {
    if (!(await this.context.isConfigured())) throw new ServiceUnavailableException('钉钉未配置');
    const token = await this.context.getAccessToken();

    const all: DingTalkShiftSummary[] = [];
    let cursor = 0;
    let hasMore = true;

    while (hasMore) {
      await this.context.rateLimit();
      const res = await fetch(
        `https://oapi.dingtalk.com/topapi/attendance/shift/list?access_token=${token}`,
        {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ op_user_id: opUserId, cursor }),
        },
      );
      const data = (await res.json()) as {
        errcode: number;
        errmsg: string;
        result?: {
          cursor?: number;
          has_more?: boolean;
          result?: Array<{ id: number; name: string }>;
        };
      };
      if (data.errcode !== 0) {
        throw new Error(`钉钉查询班次失败: ${data.errmsg} (code=${data.errcode})`);
      }

      const page = data.result;
      all.push(...(page?.result ?? []).map((s) => ({ id: s.id, name: s.name })));
      hasMore = page?.has_more ?? false;
      if (hasMore) {
        if (page?.cursor === undefined || page.cursor === cursor) {
          throw new Error('钉钉查询班次失败: 分页游标无效');
        }
        cursor = page.cursor;
      }
    }

    return all;
  }
}
