import {
    BadRequestException,
    Body,
    Controller,
    Delete,
    Get,
    NotFoundException,
    Param,
    Patch,
    Post,
    Put,
    Query,
    RawBodyRequest,
    Req,
    UseGuards,
} from '@nestjs/common';
import { Request } from 'express';
import { Throttle } from '@nestjs/throttler';
import { TransportService } from './transport.service';
import { CreateRouteDto } from './dto/create-route.dto';
import { UpdateRouteDto } from './dto/update-route.dto';
import { AssignTransportDto } from './dto/assign-transport.dto';
import { RecordTransportPaymentDto } from './dto/record-transport-payment.dto';
import { FilterTransportAssignmentsDto } from './dto/filter-transport-assignments.dto';
import { VerifyTransportPaymentDto } from './dto/verify-transport-payment.dto';
import { ToggleTransportDto } from './dto/toggle-transport.dto';
import { isValidObjectId } from 'mongoose';
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 { Role } from '../common/roles/role.enum';
import { CurrentUser } from 'src/common/decorators/current-user.decorator';
import { Public } from 'src/common/decorators/public.decorator';
import { MongoIdPipe } from 'src/common/pipes/mongo-id.pipe';
import { ReqCtx, RequestContext } from 'src/common/context/request-context';

@UseGuards(JwtAuthGuard, RolesGuard)
@Controller('transport')
export class TransportController {
    constructor(private readonly transportService: TransportService) {}

    /* =====================
       Admin: Routes CRUD
    ===================== */

    @Post('routes')
    @Roles(Role.ADMIN)
    @Throttle({ default: { limit: 10, ttl: 60000 } })
    createRoute(@Body() dto: CreateRouteDto, @ReqCtx() ctx: RequestContext) {
        return this.transportService.createRoute(dto, ctx);
    }

    @Get('routes')
    @Roles(Role.ADMIN)
    getRoutes(
        @Query('academicYearId') academicYearId?: string,
        @Query('activeOnly') activeOnly?: string,
    ) {
        return this.transportService.getRoutes(academicYearId, activeOnly === 'true');
    }

    @Get('routes/:id')
    @Roles(Role.ADMIN)
    getRoute(@Param('id', MongoIdPipe) id: string) {
        return this.transportService.getRoute(id);
    }

    @Put('routes/:id')
    @Roles(Role.ADMIN)
    updateRoute(
        @Param('id', MongoIdPipe) id: string,
        @Body() dto: UpdateRouteDto,
        @ReqCtx() ctx: RequestContext,
    ) {
        return this.transportService.updateRoute(id, dto, ctx);
    }

    @Delete('routes/:id')
    @Roles(Role.ADMIN)
    deleteRoute(@Param('id', MongoIdPipe) id: string, @ReqCtx() ctx: RequestContext) {
        return this.transportService.deleteRoute(id, ctx);
    }

    /* =====================
       Admin: Assignments
    ===================== */

    @Post('assign')
    @Roles(Role.ADMIN)
    @Throttle({ default: { limit: 5, ttl: 60000 } })
    assignStudents(@Body() dto: AssignTransportDto, @ReqCtx() ctx: RequestContext) {
        return this.transportService.assignStudents(dto, ctx);
    }

    @Post('sync-assignments')
    @Roles(Role.ADMIN)
    @Throttle({ default: { limit: 2, ttl: 60000 } })
    syncAssignments(@Query('routeId') routeId?: string) {
        if (routeId && !isValidObjectId(routeId)) {
            throw new BadRequestException('Invalid route ID');
        }
        return this.transportService.syncAssignments(routeId);
    }

    @Get('assignments')
    @Roles(Role.ADMIN)
    getAssignments(@Query() filter: FilterTransportAssignmentsDto) {
        return this.transportService.getAssignments(filter);
    }

    @Post('assignments/:id/record-payment')
    @Roles(Role.ADMIN)
    @Throttle({ default: { limit: 20, ttl: 60000 } })
    recordOfflinePayment(
        @Param('id', MongoIdPipe) id: string,
        @Body() dto: RecordTransportPaymentDto,
        @CurrentUser('id') adminId: string,
    ) {
        return this.transportService.recordOfflinePayment(id, dto, adminId);
    }

    @Patch('students/:studentId/toggle')
    @Roles(Role.ADMIN)
    @Throttle({ default: { limit: 20, ttl: 60000 } })
    toggleTransport(
        @Param('studentId', MongoIdPipe) studentId: string,
        @Body() dto: ToggleTransportDto,
        @ReqCtx() ctx: RequestContext,
    ) {
        return this.transportService.toggleTransport(studentId, dto, ctx);
    }

    @Delete('students/:studentId/remove')
    @Roles(Role.ADMIN)
    @Throttle({ default: { limit: 10, ttl: 60000 } })
    removeTransport(
        @Param('studentId', MongoIdPipe) studentId: string,
        @Query('routeId') routeId: string,
        @Query('academicYearId') academicYearId: string,
        @ReqCtx() ctx: RequestContext,
    ) {
        if (!routeId || !isValidObjectId(routeId)) {
            throw new BadRequestException('Valid routeId query parameter is required');
        }
        if (!academicYearId || !isValidObjectId(academicYearId)) {
            throw new BadRequestException('Valid academicYearId query parameter is required');
        }
        return this.transportService.removeTransport(studentId, routeId, academicYearId, ctx);
    }

    @Get('students/:studentId/status')
    @Roles(Role.ADMIN)
    @Throttle({ default: { limit: 30, ttl: 60000 } })
    getStudentTransportStatus(
        @Param('studentId', MongoIdPipe) studentId: string,
        @Query('academicYearId') academicYearId?: string,
    ) {
        return this.transportService.getStudentTransportStatus(studentId, academicYearId);
    }

    @Get('student/:studentId/dashboard')
    @Roles(Role.ADMIN)
    getStudentDashboardAdmin(
        @Param('studentId', MongoIdPipe) studentId: string,
        @Query('academicYearId') academicYearId?: string,
    ) {
        return this.transportService.getStudentDashboard(studentId, academicYearId);
    }

    /* =====================
       Student: Dashboard & Payments
    ===================== */

    @Get('my-dashboard')
    @Roles(Role.STUDENT)
    getMyDashboard(
        @CurrentUser('id') studentId: string,
        @Query('academicYearId') academicYearId?: string,
    ) {
        return this.transportService.getStudentDashboard(studentId, academicYearId);
    }

    @Post('assignments/:id/create-order')
    @Roles(Role.STUDENT)
    @Throttle({ default: { limit: 5, ttl: 60000 } })
    createOrder(
        @Param('id', MongoIdPipe) id: string,
        @CurrentUser('id') studentId: string,
    ) {
        return this.transportService.createRazorpayOrder(id, studentId);
    }

    @Post('assignments/:id/verify-payment')
    @Roles(Role.STUDENT)
    @Throttle({ default: { limit: 10, ttl: 60000 } })
    verifyPayment(
        @Param('id', MongoIdPipe) id: string,
        @CurrentUser('id') studentId: string,
        @Body() body: VerifyTransportPaymentDto,
    ) {
        return this.transportService.verifyRazorpayPayment(id, studentId, body);
    }

    /* =====================
       Public: Receipt Verification
    ===================== */

    @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.transportService.verifyReceipt(receipt.trim());
        if (!result) throw new NotFoundException('Receipt not found');
        return result;
    }

    /* =====================
       Webhook (public - no auth)
    ===================== */

    @Post('webhook')
    @Public()
    @Throttle({ default: { limit: 60, ttl: 60000 } })
    handleWebhook(@Req() req: RawBodyRequest<Request>) {
        const signature = req.headers['x-razorpay-signature'] as string | undefined;
        if (!req.rawBody) {
            throw new BadRequestException(
                'Raw body not available — ensure rawBody: true is set in NestJS bootstrap.',
            );
        }
        return this.transportService.handleWebhook(signature, req.rawBody, req.body);
    }
}
