import { TenantHeaderInterceptor } from '@backend/auth'
import { ReservationSource } from '@backend/domain'
import { ReservationState } from '@core/types'
import { Body, Controller, Get, Param, ParseIntPipe, ParseUUIDPipe, Post, Query, UseInterceptors } from '@nestjs/common'
import {
	ApiBadRequestResponse,
	ApiInternalServerErrorResponse,
	ApiOkResponse,
	ApiQuery,
	ApiTags,
	ApiUnprocessableEntityResponse,
} from '@nestjs/swagger'
import { ParseDatePipe } from '../../../common'
import { ReservationService, TimeslotService } from '../services'
import { buildManagementUrl } from '../utils'
import {
	CreateReservationRequest,
	TimeSlot,
	VerifyReservationResponse,
	WidgetCreateReservationResponse,
} from '../types'

@UseInterceptors(TenantHeaderInterceptor)
@Controller('customer/reservation')
@ApiTags('customer')
export class CustomerReservationController {
	constructor(
		private readonly _reservationService: ReservationService,
		private readonly _timeslotService: TimeslotService,
	) {}

	@Get('verify/:tableId/:query')
	@ApiOkResponse({ type: VerifyReservationResponse })
	@ApiBadRequestResponse()
	@ApiInternalServerErrorResponse()
	async verify(
		@Param('tableId', ParseUUIDPipe) tableId: string,
		@Param('query') query: string,
	): Promise<VerifyReservationResponse> {
		return this._reservationService.verifyReservation(tableId, query)
	}

	@Post()
	@ApiOkResponse({ type: WidgetCreateReservationResponse })
	@ApiBadRequestResponse()
	@ApiUnprocessableEntityResponse()
	@ApiInternalServerErrorResponse()
	async create(@Body() request: CreateReservationRequest): Promise<WidgetCreateReservationResponse> {
		const reservation = await this._reservationService.create(request, ReservationSource.widget)
		return {
			confirmed: reservation.state === ReservationState.approved,
			reservationId: reservation.id,
			state: reservation.state,
			managementUrl: buildManagementUrl(reservation.managementToken),
		}
	}

	@Get('slots/:date')
	@ApiQuery({ name: 'timezone', type: String, required: false })
	@ApiQuery({ name: 'partySize', type: Number, required: false })
	@ApiOkResponse({ type: TimeSlot, isArray: true })
	@ApiBadRequestResponse()
	@ApiInternalServerErrorResponse()
	async getTimeSlotsByDate(
		@Param('date', new ParseDatePipe()) date: Date,
		@Query('timezone') timezone?: string,
		@Query('partySize', new ParseIntPipe({ optional: true })) partySize?: number,
	): Promise<TimeSlot[]> {
		// includePopular stays off since the steering redesign: advertising the
		// historic peak pulled guests exactly where the restaurant is fullest.
		return this._timeslotService.getTimeSlotsByDate(date, timezone, { partySize })
	}
}
