import {
  Controller,
  Get,
  Post,
  Put,
  Delete,
  Param,
  Body,
  Query,
  UseGuards,
  Request,
  Res,
  UseInterceptors,
  UploadedFile,
  BadRequestException,
} from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Student } from '../entities/student.entity';
import { FileInterceptor } from '@nestjs/platform-express';
import type { Response } from 'express';
import { OccupanciesService } from './occupancies.service';
import { NotificationsService } from '../notifications/notifications.service';
import { NotificationType } from '../entities/notification.entity';
import { CheckInDto, CheckOutDto, TransferRoomDto, BatchCheckOutDto } from './dto/occupancy.dto';
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
import { OperationLogsService } from '../operation-logs/operation-logs.service';
import { extractRequestInfo } from '../common/request-utils';
import { RequirePermission } from '../auth/decorators/permission.decorator';
import * as ExcelJS from 'exceljs';
import {
  createOccupancyImportTemplateWorkbook,
  parseOccupancyImportWorksheet,
} from './occupancy-import-template';

@UseGuards(JwtAuthGuard)
@Controller('occupancies')
export class OccupanciesController {
  constructor(
    private service: OccupanciesService,
    private logService: OperationLogsService,
    private readonly notificationsService: NotificationsService,
    @InjectRepository(Student) private studentRepo: Repository<Student>,
  ) {}

  @Get()
  @RequirePermission('occupancy:view')
  findAll(
    @Query('roomId') roomId?: string,
    @Query('studentId') studentId?: string,
    @Query('active') active?: string,
  ) {
    return this.service.findAll({
      roomId: roomId ? +roomId : undefined,
      studentId: studentId ? +studentId : undefined,
      active: active === 'true',
    });
  }

  @Post('batch-check-out')
  @RequirePermission('occupancy:checkout')
  async batchCheckOut(@Body() dto: BatchCheckOutDto, @Request() req: any) {
    const { ipAddress, userAgent } = extractRequestInfo(req);
    const result = await this.service.batchCheckOut(dto);
    await this.logService.log({
      userId: req.user?.id,
      username: req.user?.username,
      module: '入住管理',
      action: '批量退宿',
      detail: `退宿 ${dto.ids.length} 人，日期 ${dto.checkOutDate}`,
      ipAddress,
      userAgent,
    });
    return result;
  }

  @Post('check-in')
  @RequirePermission('occupancy:checkin')
  async checkIn(@Body() dto: CheckInDto, @Request() req: any) {
    const { ipAddress, userAgent } = extractRequestInfo(req);
    const result = await this.service.checkIn(dto, req.user?.id);
    await this.logService.log({
      userId: req.user?.id,
      username: req.user?.username,
      module: '入住管理',
      action: '办理入住',
      targetId: result.id,
      targetType: 'occupancy',
      detail: `学生${dto.studentId} 入住房间${dto.roomId}`,
      ipAddress,
      userAgent,
    });
    // Send check_in notification
    try {
      const student = await this.studentRepo.findOne({ where: { id: dto.studentId } });
      if (student?.userId) {
        void this.notificationsService.create({
          recipientIds: [student.userId],
          type: NotificationType.CHECK_IN,
          title: '入住通知',
          content: `您已入住房间 #${dto.roomId}`,
        });
      }
    } catch (_) {
      /* don't block response */
    }
    return result;
  }

  @Put(':id/check-out')
  @RequirePermission('occupancy:checkout')
  async checkOut(@Param('id') id: string, @Body() dto: CheckOutDto, @Request() req: any) {
    const { ipAddress, userAgent } = extractRequestInfo(req);
    const result = await this.service.checkOut(+id, dto);
    await this.logService.log({
      userId: req.user?.id,
      username: req.user?.username,
      module: '入住管理',
      action: '办理退宿',
      targetId: +id,
      targetType: 'occupancy',
      ipAddress,
      userAgent,
    });
    // Send check_out notification
    try {
      const student = await this.studentRepo.findOne({ where: { id: result.studentId } });
      if (student?.userId) {
        void this.notificationsService.create({
          recipientIds: [student.userId],
          type: NotificationType.CHECK_OUT,
          title: '退宿通知',
          content: `您已退宿房间 #${result.roomId}`,
        });
      }
    } catch (_) {
      /* don't block response */
    }
    return result;
  }

  @Put(':id/transfer')
  @RequirePermission('occupancy:transfer')
  async transferRoom(@Param('id') id: string, @Body() dto: TransferRoomDto, @Request() req: any) {
    const { ipAddress, userAgent } = extractRequestInfo(req);
    const result = await this.service.transferRoom(+id, dto);
    await this.logService.log({
      userId: req.user?.id,
      username: req.user?.username,
      module: '入住管理',
      action: '调换宿舍',
      targetId: +id,
      targetType: 'occupancy',
      detail: `换到房间${dto.newRoomId}`,
      ipAddress,
      userAgent,
    });
    return result;
  }

  @Delete(':id')
  @RequirePermission('occupancy:view')
  async remove(@Param('id') id: string, @Request() req: any) {
    const { ipAddress, userAgent } = extractRequestInfo(req);
    const result = await this.service.remove(+id);
    await this.logService.log({
      userId: req.user?.id,
      username: req.user?.username,
      module: '入住管理',
      action: '归档入住记录',
      targetId: +id,
      targetType: 'occupancy',
      ipAddress,
      userAgent,
    });
    return result;
  }

  @Post('batch-delete')
  @RequirePermission('occupancy:view')
  async batchRemove(@Body() body: { ids: number[] }, @Request() req: any) {
    const { ipAddress, userAgent } = extractRequestInfo(req);
    const result = await this.service.batchRemove(body.ids || []);
    await this.logService.log({
      userId: req.user?.id,
      username: req.user?.username,
      module: '入住管理',
      action: '批量归档入住记录',
      detail: `IDs: ${(body.ids || []).join(',')}`,
      ipAddress,
      userAgent,
    });
    return result;
  }

  @Get('export')
  @RequirePermission('occupancy:view')
  async exportExcel(@Query('active') active?: string, @Res() res?: Response) {
    const records = await this.service.findAll({ active: active === 'true' });
    const workbook = new ExcelJS.Workbook();
    const ws = workbook.addWorksheet('入住记录');
    ws.columns = [
      { header: '宿舍号', key: 'roomNumber', width: 12 },
      { header: '楼栋', key: 'building', width: 12 },
      { header: '床位号', key: 'bedNumber', width: 10 },
      { header: '柜子号', key: 'lockerNumber', width: 10 },
      { header: '学生姓名', key: 'studentName', width: 12 },
      { header: '性别', key: 'gender', width: 8 },
      { header: '电话', key: 'phone', width: 18 },
      { header: '学号', key: 'studentNo', width: 15 },
      { header: '身份证号', key: 'idNumber', width: 22 },
      { header: '负责人/班主任', key: 'supervisor', width: 15 },
      { header: '入住日期', key: 'checkInDate', width: 14 },
      { header: '退宿日期', key: 'checkOutDate', width: 14 },
      { header: '计费起始', key: 'billingStartDate', width: 14 },
      { header: '计费截止', key: 'billingEndDate', width: 14 },
      { header: '入住类型', key: 'stayType', width: 10 },
      { header: '退宿原因', key: 'checkOutReason', width: 16 },
      { header: '备注', key: 'notes', width: 24 },
    ];
    ws.getRow(1).font = { bold: true };
    ws.getRow(1).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFE0E0E0' } };
    for (const r of records) {
      ws.addRow({
        roomNumber: r.room?.roomNumber || '',
        building: r.room?.building || '',
        bedNumber: r.bed?.bedNumber || '',
        lockerNumber: r.locker?.lockerNumber || '',
        studentName: r.student?.name || '',
        gender: r.student?.gender || '',
        phone: r.student?.phone || '',
        studentNo: r.student?.studentNo || '',
        idNumber: r.student?.idNumber || '',
        supervisor: r.student?.supervisor || '',
        checkInDate: r.checkInDate || '',
        checkOutDate: r.checkOutDate || '',
        billingStartDate: r.billingStartDate || '',
        billingEndDate: r.billingEndDate || '',
        stayType: r.stayType === 'long' ? '长租' : '短租',
        checkOutReason: r.checkOutReason || '',
        notes: r.notes || '',
      });
    }
    res!.setHeader(
      'Content-Type',
      'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
    );
    res!.setHeader('Content-Disposition', 'attachment; filename=occupancies.xlsx');
    await workbook.xlsx.write(res!);
    res!.end();
  }

  @Get('template')
  @RequirePermission('occupancy:view')
  async downloadTemplate(@Res() res: Response) {
    const workbook = createOccupancyImportTemplateWorkbook();
    res.setHeader(
      'Content-Type',
      'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
    );
    res.setHeader('Content-Disposition', 'attachment; filename=checkin_template.xlsx');
    await workbook.xlsx.write(res);
    res.end();
  }

  @Post('import')
  @RequirePermission('occupancy:checkin')
  @UseInterceptors(FileInterceptor('file'))
  async importCheckIn(
    @UploadedFile() file: Express.Multer.File,
    @Request() req: any,
    @Query('autoDeposit') autoDeposit?: string,
    @Query('depositAmount') depositAmount?: string,
  ) {
    const { ipAddress, userAgent } = extractRequestInfo(req);
    if (!file?.buffer) throw new BadRequestException('请上传入住名单 Excel 文件');
    const workbook = new ExcelJS.Workbook();
    await workbook.xlsx.load(file.buffer as any);
    const ws = workbook.worksheets[0];
    const rows = parseOccupancyImportWorksheet(ws);
    const result = await this.service.batchImportCheckIn(rows, {
      autoDeposit: autoDeposit === 'true',
      depositAmount: depositAmount?.trim() ? Number(depositAmount) : undefined,
    });
    await this.logService.log({
      userId: req.user?.id,
      username: req.user?.username,
      module: '入住管理',
      action: '批量导入入住',
      detail: result.message,
      ipAddress,
      userAgent,
    });
    return result;
  }
}
