import { EntityManager, IsNull } from 'typeorm';
import { Bed } from '../entities/bed.entity';
import { Locker } from '../entities/locker.entity';
import { Occupancy } from '../entities/occupancy.entity';
import { Organization } from '../entities/organization.entity';
import { Room } from '../entities/room.entity';
import { Student } from '../entities/student.entity';
import { RoomsService } from '../rooms/rooms.service';
import type { AiReviewSection } from './entities/ai-review.entity';
import { normalizePhone, toDateString } from './ai-review.shared';
import { importRooms, importStudents, nextDay } from './ai-review.import-basic';
import type { AiReviewSectionResult } from './ai-review.shared';

export async function importOneSection(
  section: AiReviewSection,
  manager: EntityManager,
): Promise<AiReviewSectionResult> {
  if (section.type === 'students') return importStudents(section, manager);
  if (section.type === 'rooms') return importRooms(section, manager);
  if (section.type === 'transfers') return importTransfers(section, manager);
  return importCheckins(section, manager);
}

async function importTransfers(
  section: AiReviewSection | undefined,
  manager: EntityManager,
): Promise<{ completed: number; skipped: number; issues: string[] }> {
  let completed = 0;
  let skipped = 0;
  const issues: string[] = [];
  if (!section || section.rows.length === 0) return { completed, skipped, issues };
  const studentRepo = manager.getRepository(Student);
  const occRepo = manager.getRepository(Occupancy);
  const roomRepo = manager.getRepository(Room);

  for (const row of section.rows) {
    const phone = normalizePhone(row.studentPhone ?? row.phone);
    const studentNo =
      row.studentNo === undefined || row.studentNo === null
        ? ''
        : String(row.studentNo).trim();
    const newRoomNumber =
      row.newRoom === undefined || row.newRoom === null
        ? ''
        : String(row.newRoom).trim();
    const transferDate = toDateString(row.transferDate ?? row.date);
    if (!newRoomNumber) {
      skipped += 1;
      issues.push('存在目标宿舍为空的行');
      continue;
    }
    if (!transferDate) {
      skipped += 1;
      issues.push(`换宿到「${newRoomNumber}」的日期格式无效（应为 YYYY-MM-DD）`);
      continue;
    }
    const student = studentNo
      ? await studentRepo.findOne({ where: { studentNo } })
      : phone
        ? await studentRepo.findOne({ where: { phone } })
        : null;
    if (!student) {
      skipped += 1;
      issues.push(`换宿到「${newRoomNumber}」的学生不存在（缺少手机号/学号）`);
      continue;
    }
    const active = await occRepo.findOne({
      where: { studentId: student.id, checkOutDate: IsNull() },
      order: { id: 'DESC' },
    });
    if (!active) {
      skipped += 1;
      issues.push(`学生「${student.name}」当前没有在住记录，无法换宿`);
      continue;
    }
    const oldRoom = await roomRepo.findOne({ where: { id: active.roomId } });
    const oldRoomNumber = oldRoom?.roomNumber ?? String(active.roomId);
    const expectedOldRoom =
      row.oldRoom === undefined || row.oldRoom === null
        ? ''
        : String(row.oldRoom).trim();
    if (expectedOldRoom && expectedOldRoom !== oldRoomNumber) {
      skipped += 1;
      issues.push(
        `学生「${student.name}」原宿舍为「${oldRoomNumber}」，与行内填写的「${expectedOldRoom}」不一致`,
      );
      continue;
    }
    const newRoom = await roomRepo.findOne({ where: { roomNumber: newRoomNumber } });
    if (!newRoom) {
      skipped += 1;
      issues.push(`学生「${student.name}」的目标宿舍「${newRoomNumber}」不存在`);
      continue;
    }
    if (newRoom.status === 'archived' || newRoom.status === 'maintenance') {
      skipped += 1;
      issues.push(`学生「${student.name}」的目标宿舍「${newRoomNumber}」当前不可入住`);
      continue;
    }
    if (newRoom.id === active.roomId) {
      skipped += 1;
      issues.push(`学生「${student.name}」的目标宿舍与当前宿舍相同`);
      continue;
    }
    if (transferDate < String(active.checkInDate)) {
      skipped += 1;
      issues.push(`学生「${student.name}」的换宿日期早于入住日期`);
      continue;
    }
    const activeCount = await occRepo.count({
      where: { roomId: newRoom.id, checkOutDate: IsNull() },
    });
    if (activeCount >= (newRoom.capacity ?? 0)) {
      skipped += 1;
      issues.push(`学生「${student.name}」的目标宿舍「${newRoomNumber}」已满`);
      continue;
    }

    active.checkOutDate = transferDate;
    active.billingEndDate = transferDate;
    active.checkOutReason = 'Excel 批量导入换宿';
    await occRepo.save(active);
    if (active.bedId) {
      await manager.getRepository(Bed).update(active.bedId, { status: 'available' });
    }
    if (active.lockerId) {
      await manager.getRepository(Locker).update(active.lockerId, { status: 'available' });
    }
    await roomRepo.update(active.roomId, { status: 'available' });

    const nextDayDate = nextDay(transferDate);
    await occRepo.save(
      occRepo.create({
        studentId: student.id,
        roomId: newRoom.id,
        checkInDate: transferDate,
        billingStartDate: nextDayDate,
        stayType: active.stayType || 'short',
        responsibleOrganizationId: active.responsibleOrganizationId ?? student.organizationId,
        notes: `从${oldRoomNumber}换入（Excel 批量导入）`,
        status: 'active',
      }),
    );
    if (activeCount + 1 >= (newRoom.capacity ?? 0)) {
      await roomRepo.update(newRoom.id, { status: 'full' });
    }
    completed += 1;
  }
  return { completed, skipped, issues };
}

/**
 * 入住记录导入：学生不存在时按本机构自动创建，宿舍不存在时自动创建，
 * 然后写入入住记录（与「入住管理」页面的批量导入语义一致）。
 */
async function importCheckins(
  section: AiReviewSection | undefined,
  manager: EntityManager,
): Promise<{ completed: number; skipped: number; issues: string[] }> {
  let completed = 0;
  let skipped = 0;
  const issues: string[] = [];
  if (!section || section.rows.length === 0) return { completed, skipped, issues };
  const studentRepo = manager.getRepository(Student);
  const roomRepo = manager.getRepository(Room);
  const occRepo = manager.getRepository(Occupancy);
  const organizationRepo = manager.getRepository(Organization);
  const seen = new Set<string>();

  for (const row of section.rows) {
    const name = row.name === undefined || row.name === null ? '' : String(row.name).trim();
    const phone = normalizePhone(row.phone);
    const studentNo =
      row.studentNo === undefined || row.studentNo === null
        ? ''
        : String(row.studentNo).trim();
    const roomNumber =
      row.roomNumber === undefined || row.roomNumber === null
        ? ''
        : String(row.roomNumber).trim();
    if (!name || !roomNumber) {
      skipped += 1;
      issues.push('存在姓名或宿舍号为空的入住记录行');
      continue;
    }
    if (!phone && !studentNo) {
      skipped += 1;
      issues.push(`学生「${name}」缺少手机号/学号，无法关联或创建学生`);
      continue;
    }
    const dedupeKey = phone ? `phone:${phone}` : `no:${studentNo}`;
    if (seen.has(dedupeKey)) {
      skipped += 1;
      issues.push(`学生「${name}」与同一批次中的其他行手机号/学号重复`);
      continue;
    }
    seen.add(dedupeKey);

    let student = phone
      ? await studentRepo.findOne({ where: { phone } })
      : await studentRepo.findOne({ where: { studentNo } });
    if (!student) {
      const hostOrganization = await organizationRepo.findOne({
        where: { isHost: true, status: 'active' },
      });
      if (!hostOrganization) {
        skipped += 1;
        issues.push(`学生「${name}」不存在且未配置本机构，无法自动创建`);
        continue;
      }
      student = await studentRepo.save(
        studentRepo.create({
          name,
          phone: phone || undefined,
          studentNo: studentNo || undefined,
          gender:
            row.gender === undefined || row.gender === null
              ? undefined
              : String(row.gender).trim().slice(0, 10),
          organizationId: hostOrganization.id,
          status: 'active',
        }),
      );
    } else if (phone && !student.phone) {
      await studentRepo.update(student.id, { phone });
      student.phone = phone;
    }

    let room = await roomRepo.findOne({ where: { roomNumber } });
    if (!room) {
      const parsed = RoomsService.parseRoomNumber(roomNumber);
      room = await roomRepo.save(
        roomRepo.create({
          roomNumber,
          building:
            row.building === undefined || row.building === null
              ? parsed.building
              : String(row.building).trim().slice(0, 50),
          floor: parsed.floor || undefined,
          capacity: parsed.capacity ?? 4,
          roomType: parsed.roomType || undefined,
          status: 'available',
        }),
      );
    }
    if (room.status === 'archived' || room.status === 'maintenance') {
      skipped += 1;
      issues.push(`学生「${name}」的目标宿舍「${roomNumber}」当前不可入住`);
      continue;
    }

    const checkInDate = toDateString(row.checkInDate) ?? new Date().toISOString().slice(0, 10);
    const billingStartDate = toDateString(row.billingStartDate) ?? checkInDate;
    const checkOutDate = toDateString(row.checkOutDate);
    const isHistoricalRecord = Boolean(checkOutDate);

    const existing = await occRepo.findOne({
      where: { studentId: student.id, checkOutDate: IsNull() },
      order: { id: 'DESC' },
    });
    if (existing && !isHistoricalRecord) {
      skipped += 1;
      issues.push(`学生「${name}」当前已在住，未重复入住`);
      continue;
    }
    const activeCount = await occRepo.count({
      where: { roomId: room.id, checkOutDate: IsNull() },
    });
    if (!isHistoricalRecord && activeCount >= (room.capacity ?? 0)) {
      skipped += 1;
      issues.push(`学生「${name}」的目标宿舍「${roomNumber}」已满`);
      continue;
    }

    await occRepo.save(
      occRepo.create({
        studentId: student.id,
        roomId: room.id,
        checkInDate,
        billingStartDate,
        ...(checkOutDate
          ? { checkOutDate, checkOutReason: 'Excel 批量导入历史入住' }
          : {}),
        stayType:
          row.stayType === undefined || row.stayType === null
            ? 'short'
            : String(row.stayType).trim().slice(0, 10) || 'short',
        responsibleOrganizationId: student.organizationId,
        notes: `Excel 批量导入入住：${roomNumber}`,
        status: 'active',
      }),
    );
    if (!isHistoricalRecord && activeCount + 1 >= (room.capacity ?? 0)) {
      await roomRepo.update(room.id, { status: 'full' });
    }
    completed += 1;
  }
  return { completed, skipped, issues };
}
