import { ReservationState } from '@core/types'
import { Column, Entity, JoinTable, ManyToMany, ManyToOne, OneToOne } from 'typeorm'
import { UserModifiableEntity } from '../entity'
import { Order } from '../order'
import { Table, TableCombination } from '../room-plan'
import { CustomerData } from './customer-data.model'
import { ReservationSource } from './enums'

@Entity()
export class Reservation extends UserModifiableEntity<Reservation> {
	@Column({
		type: 'integer',
		nullable: false,
	})
	noOfPersons: number

	@Column({
		type: 'timestamp with time zone',
		nullable: false,
	})
	startDate: Date

	@Column({
		type: 'timestamp with time zone',
		nullable: false,
	})
	endDate: Date

	@Column({
		type: 'enum',
		enum: ReservationState,
		default: ReservationState.unconfirmed,
		nullable: false,
	})
	state: ReservationState

	@Column({
		type: 'text',
		nullable: true,
	})
	comment?: string

	@Column({
		type: 'boolean',
		default: false,
		nullable: false,
	})
	reminderSent: boolean

	/**
	 * Client-provided token to deduplicate booking requests (e.g. Google Booking Server
	 * CreateBooking). Unique per tenant when set.
	 */
	@Column({
		type: 'varchar',
		length: 128,
		nullable: true,
	})
	idempotencyToken?: string

	@Column({
		type: 'enum',
		enum: ReservationSource,
		default: ReservationSource.admin,
		nullable: false,
	})
	source: ReservationSource

	/**
	 * Cryptographically random secret that authorizes guest self-service
	 * (view/update/cancel) for this reservation without an account.
	 * Globally unique when set; never expose it in logs or list responses.
	 */
	@Column({
		type: 'varchar',
		length: 64,
		nullable: true,
	})
	managementToken?: string | null

	@Column(() => CustomerData, { prefix: 'customer' })
	customerData: CustomerData

	/**
	 * Optional additional guest emails (friends of the booker). They receive the
	 * guest notifications but never the management link — only the booker may
	 * change or cancel the reservation.
	 */
	@Column({
		type: 'simple-json',
		nullable: true,
	})
	companionEmails?: string[] | null

	/**
	 * List of tables in the combination
	 */
	@ManyToMany(() => Table)
	@JoinTable({ name: 'reservation_tables' })
	tables?: Table[]

	/** If reservation tables were assigned from a table combination */
	@ManyToOne(() => TableCombination, (combination) => combination.reservations, { nullable: true })
	tableCombination?: TableCombination

	@OneToOne(() => Order, (order) => order.reservation)
	order?: Order
}

export const OpenReservationFilter = [ReservationState.unconfirmed, ReservationState.approved, ReservationState.seated]
export const ApprovedOpenReservationFilter = [ReservationState.approved, ReservationState.seated]
