import {
  Controller,
  Get,
  Post,
  Put,
  Delete,
  Body,
  Param,
  Query,
  UseGuards,
  Request,
  ParseIntPipe,
} from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Student } from '../entities/student.entity';
import { DepositsService } from './deposits.service';
import { NotificationsService } from '../notifications/notifications.service';
import {
  BatchCreateDepositDto,
  CreateDepositDto,
  CreateDepositInstallmentDto,
  RefundDepositDto,
  UpdateDepositInstallmentDto,
} from './dto/deposit.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';

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

  @Get('student-lookups')
  @RequirePermission('deposit:create')
  getStudentLookups() {
    return this.service.getStudentLookups();
  }


  @Get('eligible-students')
  @RequirePermission('deposit:view')
  getEligibleStudents(@Query('roomType') roomType?: string) {
    return this.service.getEligibleStudents(roomType || undefined);
  }

  @Get()
  @RequirePermission('deposit:view')
  findAll(
    @Query('studentId', new ParseIntPipe({ optional: true })) studentId?: number,
    @Query('status') status?: string,
  ) {
    return this.service.findAll({
      studentId,
      status: status || undefined,
    });
  }

  @Get('stats')
  @RequirePermission('deposit:view')
  getStats() {
    return this.service.getStats();
  }

  @Get(':id')
  @RequirePermission('deposit:view')
  findOne(@Param('id', ParseIntPipe) id: number) {
    return this.service.findOne(id);
  }

  @Post()
  @RequirePermission('deposit:create')
  async create(@Body() dto: CreateDepositDto, @Request() req: any) {
    const { ipAddress, userAgent } = extractRequestInfo(req);
    const result = await this.service.create(dto, req.user?.id);
    await this.logService.log({
      userId: req.user?.id,
      username: req.user?.username,
      module: '押金管理',
      action: '收取押金',
      targetId: result.id,
      targetType: 'deposit',
      detail: `学生${dto.studentId} ¥${dto.amount}`,
      ipAddress,
      userAgent,
    });
    // Send deposit_due notification
    try {
      const student = await this.studentRepo.findOne({ where: { id: dto.studentId } });
      if (student?.userId) {
        void this.notificationsService.create({
          recipientIds: [student.userId],
          type: 'deposit_due',
          title: '押金待缴',
          content: `您有一笔押金待缴纳,金额: ¥${dto.amount}`,
        });
      }
    } catch (_) { /* don't block response */ }
    return result;
  }


  @Post('batch')
  @RequirePermission('deposit:create')
  async batchCreate(@Body() dto: BatchCreateDepositDto, @Request() req: any) {
    const { ipAddress, userAgent } = extractRequestInfo(req);
    const result = await this.service.batchCreate(dto, req.user?.id);
    await this.logService.log({
      userId: req.user?.id,
      username: req.user?.username,
      module: '押金管理',
      action: '批量收取押金',
      targetType: 'deposit',
      detail: `批量收取${result.count}人，每人¥${result.amount}${dto.roomType ? `，房型：${dto.roomType}` : ''}${dto.notes ? `，备注：${dto.notes}` : ''}`,
      ipAddress,
      userAgent,
    });
    return result;
  }

  @Post(':id/installments')
  @RequirePermission('deposit:edit')
  async addInstallment(
    @Param('id', ParseIntPipe) id: number,
    @Body() body: CreateDepositInstallmentDto,
    @Request() req: { user?: { id: number; username: string }; headers?: Record<string, string> },
  ) {
    const { ipAddress, userAgent } = extractRequestInfo(req);
    const result = await this.service.addInstallment(id, body.amount, body.dueDate);
    await this.logService.log({
      userId: req.user?.id,
      username: req.user?.username,
      module: '押金管理',
      action: '新增分期',
      targetId: result.id,
      targetType: 'deposit-installment',
      detail: `押金${id} 新增分期 ¥${result.amount}`,
      ipAddress,
      userAgent,
    });
    return result;
  }

  @Put('installments/:installmentId')
  @RequirePermission('deposit:edit')
  async updateInstallment(
    @Param('installmentId', ParseIntPipe) installmentId: number,
    @Body() body: UpdateDepositInstallmentDto,
    @Request() req: { user?: { id: number; username: string }; headers?: Record<string, string> },
  ) {
    const { ipAddress, userAgent } = extractRequestInfo(req);
    const result = await this.service.updateInstallment(installmentId, body);
    await this.logService.log({
      userId: req.user?.id,
      username: req.user?.username,
      module: '押金管理',
      action: '更新分期',
      targetId: installmentId,
      targetType: 'deposit-installment',
      detail: `更新分期${installmentId}, 状态：${result.status ?? '-'}, 实付日：${result.paidDate ?? '-'}`,
      ipAddress,
      userAgent,
    });
    return result;
  }

  @Delete('installments/:installmentId')
  @RequirePermission('deposit:delete')
  async deleteInstallment(
    @Param('installmentId', ParseIntPipe) installmentId: number,
    @Request() req: { user?: { id: number; username: string }; headers?: Record<string, string> },
  ) {
    const { ipAddress, userAgent } = extractRequestInfo(req);
    const result = await this.service.deleteInstallment(installmentId);
    await this.logService.log({
      userId: req.user?.id,
      username: req.user?.username,
      module: '押金管理',
      action: '归档分期',
      targetId: installmentId,
      targetType: 'deposit-installment',
      detail: `归档分期${installmentId}`,
      ipAddress,
      userAgent,
    });
    return result;
  }

  @Put(':id/refund')
  @RequirePermission('deposit:refund')
  async refund(@Param('id', ParseIntPipe) id: number, @Body() dto: RefundDepositDto, @Request() req: any) {
    const { ipAddress, userAgent } = extractRequestInfo(req);
    const result = await this.service.refund(id, dto, req.user?.id);
    await this.logService.log({
      userId: req.user?.id,
      username: req.user?.username,
      module: '押金管理',
      action: '退还押金',
      targetId: id,
      targetType: 'deposit',
      detail: `退还全部可用押金 ¥${result.refundAmount}`,
      ipAddress,
      userAgent,
    });
    // Send deposit_refunded notification
    try {
      const student = await this.studentRepo.findOne({ where: { id: result.studentId } });
      if (student?.userId) {
        void this.notificationsService.create({
          recipientIds: [student.userId],
          type: 'deposit_refunded',
          title: '押金已退还',
          content: `您的剩余押金已全部退还,金额: ¥${result.refundAmount}`,
        });
      }
    } catch (_) { /* don't block response */ }
    return result;
  }

  @Delete(':id')
  @RequirePermission('deposit:delete')
  async remove(@Param('id', ParseIntPipe) id: number, @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: 'deposit',
      ipAddress,
      userAgent,
    });
    return result;
  }
}
