import {
    Controller, Get, Post, Put, Patch, Delete,
    Body, Param, Query, Req, UseGuards,
    BadRequestException, NotFoundException,
} from '@nestjs/common';
import { Throttle } from '@nestjs/throttler';
import { JwtAuthGuard } from 'src/common/guards/jwt-auth.guard';
import { RolesGuard } from 'src/common/guards/roles.guard';
import { Roles } from 'src/common/decorators/roles.decorator';
import { Public } from 'src/common/decorators/public.decorator';
import { Role } from 'src/common/roles/role.enum';
import { CurrentUser } from 'src/common/decorators/current-user.decorator';
import { MongoIdPipe } from 'src/common/pipes/mongo-id.pipe';
import { InvoicesService } from './invoices.service';
import { CreateInvoiceDto } from './dto/create-invoice.dto';
import { UpdateInvoiceDto } from './dto/update-invoice.dto';
import { FilterInvoicesDto } from './dto/filter-invoices.dto';

@UseGuards(JwtAuthGuard, RolesGuard)
@Controller('invoices')
export class InvoicesController {
    constructor(private readonly invoicesService: InvoicesService) {}

    @Post()
    @Roles(Role.ADMIN)
    @Throttle({ default: { limit: 10, ttl: 60000 } })
    create(
        @Body() dto: CreateInvoiceDto,
        @Req() req: Request & { __ctx?: any },
    ) {
        const academicYearId = (req as any).__ctx?.academicYearId;
        return this.invoicesService.create(dto, academicYearId);
    }

    @Get()
    @Roles(Role.ADMIN, Role.STUDENT)
    findAll(
        @Query() filter: FilterInvoicesDto,
        @CurrentUser('id') userId: string,
        @CurrentUser('role') role: string,
        @Req() req: Request & { __ctx?: any },
    ) {
        // Students can only list their own invoices — force-override studentId
        // regardless of any query-string value to prevent enumeration.
        if (role === Role.STUDENT) filter.studentId = userId;
        const academicYearId = filter.academicYearId || (req as any).__ctx?.academicYearId;
        return this.invoicesService.findAll(filter, academicYearId);
    }

    // IMPORTANT: 'export' must be before ':id' to avoid matching as a MongoId
    @Get('export')
    @Roles(Role.ADMIN)
    exportInvoices(
        @Query() filter: FilterInvoicesDto,
        @Req() req: Request & { __ctx?: any },
    ) {
        const academicYearId = filter.academicYearId || (req as any).__ctx?.academicYearId;
        return this.invoicesService.exportAll(filter, academicYearId);
    }

    // Public receipt verification. Mirrors /fees/verify-receipt so a QR scan on
    // a manual-invoice receipt confirms the invoice without authentication.
    // IMPORTANT: must be placed BEFORE the `:id` route so the literal path wins.
    @Get('verify-receipt')
    @Public()
    @Throttle({ default: { limit: 10, ttl: 60000 } })
    async verifyReceipt(@Query('receipt') receipt: string) {
        if (!receipt || typeof receipt !== 'string' || receipt.length > 50) {
            throw new BadRequestException('Invalid receipt number');
        }
        const result = await this.invoicesService.verifyReceipt(receipt.trim());
        if (!result) throw new NotFoundException('Receipt not found');
        return result;
    }

    @Get(':id')
    @Roles(Role.ADMIN)
    findOne(@Param('id', MongoIdPipe) id: string) {
        return this.invoicesService.findOne(id);
    }

    @Put(':id')
    @Roles(Role.ADMIN)
    @Throttle({ default: { limit: 10, ttl: 60000 } })
    update(
        @Param('id', MongoIdPipe) id: string,
        @Body() dto: UpdateInvoiceDto,
    ) {
        return this.invoicesService.update(id, dto);
    }

    @Patch(':id/toggle-active')
    @Roles(Role.ADMIN)
    @Throttle({ default: { limit: 20, ttl: 60000 } })
    toggleActive(@Param('id', MongoIdPipe) id: string) {
        return this.invoicesService.toggleActive(id);
    }

    @Delete(':id')
    @Roles(Role.ADMIN)
    @Throttle({ default: { limit: 5, ttl: 60000 } })
    delete(@Param('id', MongoIdPipe) id: string) {
        return this.invoicesService.delete(id);
    }
}
