import {
  Controller,
  Get,
  Post,
  Patch,
  Delete,
  Body,
  Param,
  Query,
  ParseUUIDPipe,
  UseGuards,
} from '@nestjs/common';
import { JwtAuthGuard } from '../../auth/guards/jwt-auth.guard';
import { PermissionGuard } from '../../auth/guards/permission.guard';
import { Permissions } from '../../auth/decorators/permissions.decorator';
import { Lookup } from '../../common/decorators/lookup.decorator';
import { ModuleName, AccessLevel } from '../../entities/role-permission.entity';
import { PaginationDto } from '../../common/dto/pagination.dto';
import { successResponse, paginatedResponse } from '../../common/responses/api-response';
import { ActivityTicketService } from './activity-ticket.service';
import { CreateActivityTicketBatchDto } from './dto/create-activity-ticket-batch.dto';
import { UpdateActivityTicketBatchDto } from './dto/update-activity-ticket-batch.dto';
import { TopUpBatchDto } from './dto/topup-batch.dto';
import { AssignTicketDto } from './dto/assign-ticket.dto';
import { UpdateTicketItemDto } from './dto/update-ticket-item.dto';
import { TicketBatchStatus } from '../../entities/activity-ticket-batch.entity';

@Controller('activity-ticket-batches')
@UseGuards(JwtAuthGuard, PermissionGuard)
export class ActivityTicketController {
  constructor(private readonly service: ActivityTicketService) {}

  // Lookup — available batches for a given activity (used by Movement Dashboard)
  @Get('lookup')
  @Lookup()
  async lookup(@Query('activity_id') activityId: string) {
    const batches = await this.service.findActiveBatchesForActivity(activityId);
    return successResponse(batches, 'Activity ticket batches lookup');
  }

  /**
   * Returns active batches whose booking_reference_no matches the given bookingId.
   * Used by Movement Dashboard ticket assignment to show only booking-linked batches.
   * Registered BEFORE :id route to avoid UUID parse conflict.
   */
  @Get('for-booking/:bookingId')
  @Lookup()
  async getForBooking(
    @Param('bookingId') bookingId: string,
    @Query('activityId') activityId?: string,
  ) {
    const batches = await this.service.findBatchesForBooking(bookingId, activityId);
    return successResponse(batches, 'Batches for booking');
  }

  @Get()
  @Permissions({ module: ModuleName.ACTIVITY_TICKET, accessLevel: AccessLevel.VIEW })
  async findAll(
    @Query() query: PaginationDto,
    @Query('activity_id') activityId?: string,
    @Query('status') status?: TicketBatchStatus,
  ) {
    const { items, meta } = await this.service.findAllBatches({
      ...query,
      activity_id: activityId,
      status,
    });
    return paginatedResponse(items, meta, 'Ticket batches fetched successfully');
  }

  @Get(':id')
  @Permissions({ module: ModuleName.ACTIVITY_TICKET, accessLevel: AccessLevel.VIEW })
  async findOne(@Param('id', ParseUUIDPipe) id: string) {
    const batch = await this.service.findBatchById(id);
    return successResponse(batch, 'Ticket batch fetched successfully');
  }

  /**
   * Bookings whose travel window (query.start_date .. query.end_date)
   * falls entirely within this batch's validity window
   * (batch.valid_from .. batch.valid_to) AND which have at least one
   * activity item for the batch's activity_id. Drives the "Matching
   * bookings" panel on the batch detail page so ops can see which
   * bookings the batch can cover.
   */
  @Get(':id/matching-bookings')
  @Permissions({ module: ModuleName.ACTIVITY_TICKET, accessLevel: AccessLevel.VIEW })
  async matchingBookings(@Param('id', ParseUUIDPipe) id: string) {
    const items = await this.service.findMatchingBookings(id);
    return successResponse(items, 'Matching bookings fetched');
  }

  @Post()
  @Permissions({ module: ModuleName.ACTIVITY_TICKET, accessLevel: AccessLevel.CREATE })
  async create(@Body() dto: CreateActivityTicketBatchDto) {
    const result = await this.service.createBatch(dto);
    return successResponse(result.batches, result.message);
  }

  @Patch(':id')
  @Permissions({ module: ModuleName.ACTIVITY_TICKET, accessLevel: AccessLevel.EDIT })
  async update(@Param('id', ParseUUIDPipe) id: string, @Body() dto: UpdateActivityTicketBatchDto) {
    const result = await this.service.updateBatch(id, dto);
    return successResponse(result, result.message);
  }

  // Top-up: add more tickets to an existing batch (includes document upload)
  @Post(':id/topup')
  @Permissions({ module: ModuleName.ACTIVITY_TICKET, accessLevel: AccessLevel.EDIT })
  async topUp(@Param('id', ParseUUIDPipe) id: string, @Body() dto: TopUpBatchDto) {
    const result = await this.service.topUpBatch(id, dto);
    return successResponse(result, result.message);
  }

  @Delete(':id')
  @Permissions({ module: ModuleName.ACTIVITY_TICKET, accessLevel: AccessLevel.DELETE })
  async remove(@Param('id', ParseUUIDPipe) id: string) {
    const result = await this.service.deleteBatch(id);
    return successResponse(result, result.message);
  }

  // Ticket item endpoints — assign/unassign/update individual tickets
  @Post('items/assign')
  @Permissions({ module: ModuleName.ACTIVITY_TICKET, accessLevel: AccessLevel.EDIT })
  async assign(@Body() dto: AssignTicketDto) {
    const result = await this.service.assignTicket(dto);
    return successResponse(result, result.message);
  }

  @Post('items/:ticketId/unassign')
  @Permissions({ module: ModuleName.ACTIVITY_TICKET, accessLevel: AccessLevel.EDIT })
  async unassign(@Param('ticketId', ParseUUIDPipe) ticketId: string) {
    const result = await this.service.unassignTicket(ticketId);
    return successResponse(result, result.message);
  }

  @Patch('items/:ticketId')
  @Permissions({ module: ModuleName.ACTIVITY_TICKET, accessLevel: AccessLevel.EDIT })
  async updateItem(
    @Param('ticketId', ParseUUIDPipe) ticketId: string,
    @Body() dto: UpdateTicketItemDto,
  ) {
    const result = await this.service.updateTicketItem(ticketId, dto);
    return successResponse(result, result.message);
  }

  // Get all tickets assigned to a specific booking activity item
  @Get('items/by-booking-activity/:bookingActivityItemId')
  @Permissions({ module: ModuleName.ACTIVITY_TICKET, accessLevel: AccessLevel.VIEW })
  async getByBookingActivity(
    @Param('bookingActivityItemId', ParseUUIDPipe) bookingActivityItemId: string,
  ) {
    const items = await this.service.getTicketsForBookingActivityItem(bookingActivityItemId);
    return successResponse(items, 'Tickets fetched successfully');
  }

  // Full journey/history log for a ticket item
  @Get('items/:ticketId/journey')
  @Permissions({ module: ModuleName.ACTIVITY_TICKET, accessLevel: AccessLevel.VIEW })
  async getJourney(@Param('ticketId', ParseUUIDPipe) ticketId: string) {
    const events = await this.service.getTicketJourney(ticketId);
    return successResponse(events, 'Ticket journey fetched');
  }
}
