import { In, Repository } from 'typeorm';
import { AttendanceDevice } from '../entities/attendance-device.entity';
import type { AttendanceRecord } from '../entities/attendance-record.entity';

function formatDeviceDetail(device: AttendanceDevice): string {
  const classroomName = device.classroom?.name;
  return classroomName ? `${device.deviceName} · ${classroomName}` : device.deviceName;
}

/**
 * 为考勤记录补充打卡设备名称：
 * 优先按设备序列号匹配，其次按教室绑定的设备兜底。
 */
export async function attachAttendanceDeviceMappings<T extends AttendanceRecord>(
  records: T[],
  attendanceDeviceRepo: Repository<AttendanceDevice>,
  classroomId?: number | null,
): Promise<T[]> {
  if (records.length === 0) return records;
  const sns = [
    ...new Set(records.map((record) => record.punchDeviceId?.trim()).filter(Boolean) as string[]),
  ];
  const devicesBySn = new Map<string, AttendanceDevice>();
  if (sns.length > 0) {
    const devices = await attendanceDeviceRepo.find({
      where: { deviceSn: In(sns) },
      relations: ['classroom'],
    });
    for (const device of devices) devicesBySn.set(device.deviceSn, device);
  }

  const classroomIds = [
    ...new Set([
      ...records.map((record) => record.classId).filter((id): id is number => id != null),
      ...(classroomId != null ? [classroomId] : []),
    ]),
  ];
  const devicesByClassroom = new Map<number, AttendanceDevice>();
  if (classroomIds.length > 0) {
    const devices = await attendanceDeviceRepo.find({
      where: { classroomId: In(classroomIds), status: 'active' },
      relations: ['classroom'],
      order: { id: 'ASC' },
    });
    for (const device of devices) {
      if (!devicesByClassroom.has(device.classroomId)) devicesByClassroom.set(device.classroomId, device);
    }
  }

  for (const record of records) {
    const sn = record.punchDeviceId?.trim();
    const mappedBySn = sn ? devicesBySn.get(sn) : undefined;
    if (mappedBySn) {
      record.punchDeviceName = formatDeviceDetail(mappedBySn);
      record.punchDeviceId = mappedBySn.deviceSn;
      continue;
    }
    const source = (record.punchSource || '').trim().toUpperCase();
    const isMachine = ['ATM', 'ATTENDANCE_MACHINE', 'MACHINE', 'DEVICE'].some(
      (value) => source === value || source.includes(value),
    );
    const fallbackClassroomId = record.classId ?? classroomId ?? undefined;
    const mappedByClassroom = fallbackClassroomId
      ? devicesByClassroom.get(fallbackClassroomId)
      : undefined;
    if (isMachine && mappedByClassroom && !record.punchDeviceName) {
      record.punchDeviceName = formatDeviceDetail(mappedByClassroom);
      record.punchDeviceId = record.punchDeviceId || mappedByClassroom.deviceSn;
    }
  }
  return records;
}
