import {
  Controller,
  Get,
  Post,
  Put,
  Delete,
  Body,
  Param,
  Query,
  UseGuards,
  Request,
  Res,
  UseInterceptors,
  UploadedFile,
} from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import type { Response } from 'express';
import { RoomsService } from './rooms.service';
import { CreateRoomDto, UpdateRoomDto } from './dto/room.dto';
import { CreateBedDto, UpdateBedDto, BatchCreateBedDto } from './dto/bed.dto';
import { CreateLockerDto, UpdateLockerDto, BatchCreateLockerDto } from './dto/locker.dto';
import { UpdateRoomInspectionDto } from './dto/room-inspection.dto';
import { RoomInspectionsService } from './room-inspections.service';
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';

@UseGuards(JwtAuthGuard)
@Controller('rooms')
export class RoomsController {
  constructor(
    private service: RoomsService,
    private logService: OperationLogsService,
    private inspectionsService: RoomInspectionsService,
  ) {}

  @Get()
  @RequirePermission('room:view')
  findAll(
    @Query('building') building?: string,
    @Query('includeArchived') includeArchived?: string,
  ) {
    return this.service.findAll({ building, includeArchived: includeArchived === 'true' });
  }

  @Get('overview')
  @RequirePermission('room:view')
  getOverview(@Query('includeArchived') includeArchived?: string) {
    return this.service.getRoomOverview({ includeArchived: includeArchived === 'true' });
  }

  @Get('visual')
  @RequirePermission('room:view')
  getVisual(@Query('asOf') asOf?: string) {
    return this.service.getRoomVisual(asOf);
  }

  @Put(':roomId/inspections/:date')
  @RequirePermission('room:inspect')
  async updateInspection(
    @Param('roomId') roomId: string,
    @Param('date') date: string,
    @Body() dto: UpdateRoomInspectionDto,
    @Request() req: any,
  ) {
    const { ipAddress, userAgent } = extractRequestInfo(req);
    const result = await this.inspectionsService.submit(
      +roomId,
      date,
      dto.presentOccupancyIds,
      { id: req.user?.id, username: req.user?.username },
    );
    await this.logService.log({
      userId: req.user?.id,
      username: req.user?.username,
      module: '宿舍查寝',
      action: result.isUpdate ? '修改查寝记录' : '提交查寝记录',
      targetId: +roomId,
      targetType: 'room',
      detail: `查寝日期: ${date}, 宿舍: ${result.roomNumber}, 在寝: ${result.presentNames.join('、') || '无'}, 缺勤: ${result.absentNames.join('、') || '无'}`,
      ipAddress,
      userAgent,
    });
    return result.inspection;
  }

  @Get('template')
  @RequirePermission('room:view')
  async downloadTemplate(@Res() res: Response) {
    const workbook = new ExcelJS.Workbook();
    const ws = workbook.addWorksheet('宿舍导入模板');
    ws.columns = [
      { header: '房间号', key: 'roomNumber', width: 12 },
      { header: '楼栋', key: 'building', width: 12 },
      { header: '楼层', key: 'floor', width: 8 },
      { header: '额定人数', key: 'capacity', width: 10 },
      { header: '宿舍类型', key: 'roomType', width: 12 },
      { header: '租赁类型(long/short)', key: 'rentalCategory', width: 18 },
      { header: '月租金', key: 'monthlyRate', width: 10 },
    ];
    ws.addRow({
      roomNumber: '4-102',
      building: '4号楼',
      floor: 1,
      capacity: 4,
      roomType: '四人间',
      rentalCategory: 'long',
      monthlyRate: 800,
    });
    ws.addRow({
      roomNumber: '2-201',
      building: '2号楼',
      floor: 2,
      capacity: 1,
      roomType: '单人间',
      rentalCategory: 'short',
      monthlyRate: 0,
    });
    res.setHeader(
      'Content-Type',
      'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
    );
    res.setHeader('Content-Disposition', 'attachment; filename=room_template.xlsx');
    await workbook.xlsx.write(res);
    res.end();
  }

  @Get('export')
  @RequirePermission('room:view')
  async exportExcel(@Query('includeArchived') includeArchived?: string, @Res() res?: Response) {
    const rooms = await this.service.getRoomOverview({
      includeArchived: includeArchived === 'true',
    });
    const workbook = new ExcelJS.Workbook();
    const ws = workbook.addWorksheet('宿舍列表');
    ws.columns = [
      { header: '房间号', key: 'roomNumber', width: 12 },
      { header: '楼栋', key: 'building', width: 12 },
      { header: '楼层', key: 'floor', width: 8 },
      { header: '宿舍类型', key: 'roomType', width: 12 },
      { header: '额定人数', key: 'capacity', width: 10 },
      { header: '当前入住', key: 'currentCount', width: 10 },
      { header: '状态', key: 'status', width: 10 },
      { header: '租赁类型', key: 'rentalCategory', width: 12 },
      { header: '月租金', key: 'monthlyRate', width: 10 },
    ];
    ws.getRow(1).font = { bold: true };
    ws.getRow(1).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFE0E0E0' } };
    const statusMap: Record<string, string> = {
      available: '可入住',
      full: '已满',
      maintenance: '维修中',
      archived: '已归档',
    };
    for (const r of rooms) {
      ws.addRow({
        roomNumber: r.roomNumber,
        building: r.building || '',
        floor: r.floor || '',
        roomType: r.roomType || '',
        capacity: r.capacity,
        currentCount: r.currentCount,
        status: statusMap[r.status] || r.status,
        rentalCategory: r.rentalCategory === 'long' ? '长租' : '短租',
        monthlyRate: r.monthlyRate ?? '',
      });
    }
    res!.setHeader(
      'Content-Type',
      'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
    );
    res!.setHeader('Content-Disposition', 'attachment; filename=rooms.xlsx');
    await workbook.xlsx.write(res!);
    res!.end();
  }

  // ── 床位管理 ──

  @Get(':roomId/beds')
  @RequirePermission('room:view')
  getBeds(@Param('roomId') roomId: string) {
    return this.service.getRoomBeds(+roomId);
  }

  @Get(':roomId/beds/available')
  @RequirePermission('room:view')
  getAvailableBeds(@Param('roomId') roomId: string) {
    return this.service.getRoomAvailableBeds(+roomId);
  }

  @Post(':roomId/beds')
  @RequirePermission('room:edit')
  createBed(@Param('roomId') roomId: string, @Body() dto: CreateBedDto) {
    return this.service.createBed(+roomId, dto);
  }

  @Put(':roomId/beds/:id')
  @RequirePermission('room:edit')
  updateBed(@Param('roomId') roomId: string, @Param('id') id: string, @Body() dto: UpdateBedDto) {
    return this.service.updateBed(+roomId, +id, dto);
  }

  @Delete(':roomId/beds/:id')
  @RequirePermission('room:edit')
  deleteBed(@Param('roomId') roomId: string, @Param('id') id: string) {
    return this.service.deleteBed(+roomId, +id);
  }

  @Post(':roomId/beds/batch')
  @RequirePermission('room:edit')
  batchCreateBeds(@Param('roomId') roomId: string, @Body() dto: BatchCreateBedDto) {
    return this.service.batchCreateBeds(+roomId, dto);
  }

  // ── 柜子管理 ──

  @Get(':roomId/lockers')
  @RequirePermission('room:view')
  getLockers(@Param('roomId') roomId: string) {
    return this.service.getRoomLockers(+roomId);
  }

  @Get(':roomId/lockers/available')
  @RequirePermission('room:view')
  getAvailableLockers(@Param('roomId') roomId: string) {
    return this.service.getRoomAvailableLockers(+roomId);
  }

  @Post(':roomId/lockers')
  @RequirePermission('room:edit')
  createLocker(@Param('roomId') roomId: string, @Body() dto: CreateLockerDto) {
    return this.service.createLocker(+roomId, dto);
  }

  @Put(':roomId/lockers/:id')
  @RequirePermission('room:edit')
  updateLocker(
    @Param('roomId') roomId: string,
    @Param('id') id: string,
    @Body() dto: UpdateLockerDto,
  ) {
    return this.service.updateLocker(+roomId, +id, dto);
  }

  @Delete(':roomId/lockers/:id')
  @RequirePermission('room:edit')
  deleteLocker(@Param('roomId') roomId: string, @Param('id') id: string) {
    return this.service.deleteLocker(+roomId, +id);
  }

  @Post(':roomId/lockers/batch')
  @RequirePermission('room:edit')
  batchCreateLockers(@Param('roomId') roomId: string, @Body() dto: BatchCreateLockerDto) {
    return this.service.batchCreateLockers(+roomId, dto);
  }
  @Get(':id')
  @RequirePermission('room:view')
  findOne(@Param('id') id: string) {
    return this.service.findOneWithOccupants(+id);
  }

  @Post()
  @RequirePermission('room:create')
  async create(@Body() dto: CreateRoomDto, @Request() req: any) {
    const { ipAddress, userAgent } = extractRequestInfo(req);
    const result = await this.service.create(dto);
    await this.logService.log({
      userId: req.user?.id,
      username: req.user?.username,
      module: '宿舍',
      action: '添加宿舍',
      detail: `房间号: ${dto.roomNumber}, 楼栋: ${dto.building || '无'}, 额定: ${dto.capacity}人`,
      ipAddress,
      userAgent,
    });
    return result;
  }

  @Put(':id')
  @RequirePermission('room:edit')
  async update(@Param('id') id: string, @Body() dto: UpdateRoomDto, @Request() req: any) {
    const { ipAddress, userAgent } = extractRequestInfo(req);
    const result = await this.service.update(+id, dto);
    await this.logService.log({
      userId: req.user?.id,
      username: req.user?.username,
      module: '宿舍',
      action: '编辑宿舍',
      targetId: +id,
      targetType: 'room',
      detail: JSON.stringify(dto),
      ipAddress,
      userAgent,
    });
    return result;
  }

  @Delete(':id')
  @RequirePermission('room:delete')
  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: 'room',
      ipAddress,
      userAgent,
    });
    return result;
  }

  @Post('batch-delete')
  @RequirePermission('room:delete')
  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;
  }

  @Put(':id/restore')
  @RequirePermission('room:edit')
  async restore(@Param('id') id: string, @Request() req: any) {
    const { ipAddress, userAgent } = extractRequestInfo(req);
    const result = await this.service.restore(+id);
    await this.logService.log({
      userId: req.user?.id,
      username: req.user?.username,
      module: '宿舍',
      action: '恢复宿舍',
      targetId: +id,
      targetType: 'room',
      ipAddress,
      userAgent,
    });
    return result;
  }

  @Post('import')
  @RequirePermission('room:create')
  @UseInterceptors(FileInterceptor('file'))
  async importExcel(@UploadedFile() file: Express.Multer.File, @Request() req: any) {
    const { ipAddress, userAgent } = extractRequestInfo(req);
    const workbook = new ExcelJS.Workbook();
    await workbook.xlsx.load(file.buffer as any);
    const ws = workbook.worksheets[0];
    const rows: {
      roomNumber: string;
      building?: string;
      floor?: number;
      capacity?: number;
      roomType?: string;
      rentalCategory?: string;
      monthlyRate?: number;
    }[] = [];
    ws.eachRow((row, idx) => {
      if (idx === 1) return;
      const rentalCategoryRaw = String(row.getCell(6).value || '')
        .trim()
        .toLowerCase();
      const rentalCategory =
        rentalCategoryRaw === 'long' || rentalCategoryRaw === 'short'
          ? rentalCategoryRaw
          : undefined;
      const monthlyRateRaw = Number(row.getCell(7).value);
      const monthlyRate = isNaN(monthlyRateRaw) ? undefined : monthlyRateRaw;
      rows.push({
        roomNumber: String(row.getCell(1).value || ''),
        building: String(row.getCell(2).value || '') || undefined,
        floor: (n => Number.isNaN(n) ? undefined : n)(Number(row.getCell(3).value)),
        capacity: Number(row.getCell(4).value) || 4,
        roomType: String(row.getCell(5).value || '').trim() || undefined,
        rentalCategory,
        monthlyRate,
      });
    });
    const result = await this.service.batchImport(rows);
    await this.logService.log({
      userId: req.user?.id,
      username: req.user?.username,
      module: '宿舍',
      action: '批量导入',
      detail: result.message,
      ipAddress,
      userAgent,
    });
    return result;
  }
}
