import { ConnectionPositionPair, FlexibleConnectedPositionStrategy, Overlay, OverlayRef } from '@angular/cdk/overlay'
import { TemplatePortal } from '@angular/cdk/portal'
import { DatePipe, NgClass } from '@angular/common'
import { Component, ElementRef, inject, TemplateRef, viewChild, ViewContainerRef } from '@angular/core'
import { FormControl, ReactiveFormsModule } from '@angular/forms'
import { Router } from '@angular/router'
import { DefaultService, ReservationResponse, TableResponse } from '@api-client/angular'
import { TranslocoDirective } from '@jsverse/transloco'
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'
import { BehaviorSubject, combineLatest, debounceTime, distinctUntilChanged, map, of, switchMap, tap } from 'rxjs'
import { ReservationView } from '../../../views/reservations/reservation.types'
import { SettingsStore } from '../../../+state'
import { LucideUser } from '@lucide/angular'

@UntilDestroy({ checkProperties: true })
@Component({
	selector: 'kadi-reservation-search',
	templateUrl: './reservation-search.component.html',
	styles: [
		`
			.shadow-custom {
				box-shadow: 0 0 4px 2px rgba(0, 0, 0, 0.1);
			}
		`,
	],
	imports: [TranslocoDirective, ReactiveFormsModule, NgClass, DatePipe, LucideUser],
})
export class ReservationSearchComponent {
	readonly _settingsStore = inject(SettingsStore)
	readonly originElement = viewChild.required<ElementRef<HTMLInputElement>>('origin')
	readonly reservationsTemplate = viewChild.required<TemplateRef<HTMLElement>>('reservationsTemplate')
	readonly reservationsContainer = viewChild.required('reservationsContainer', { read: ViewContainerRef })
	isOverlayOpen = false
	overlayRef: OverlayRef | undefined
	ReservationState = ReservationResponse.StateEnum
	searchControl = new FormControl('', { nonNullable: true })
	tables: TableResponse[] = []
	reservations: ReservationView[] = []
	private readonly _router = inject(Router)
	private readonly _overlay = inject(Overlay)
	private readonly _apiService = inject(DefaultService)
	private readonly actionSuccessSubject = new BehaviorSubject<void>(void 0)
	readonly actionSuccess$ = this.actionSuccessSubject.asObservable()

	constructor() {
		this.loadTables()

		combineLatest([
			this.searchControl.valueChanges.pipe(distinctUntilChanged(), debounceTime(300)),
			this.actionSuccess$,
		])
			.pipe(
				untilDestroyed(this),
				switchMap(([query]) => {
					if (query && query.length > 0) {
						return this._apiService.reservationControllerSearchByQuery(query, true).pipe(
							switchMap((reservations) => {
								if (reservations.length > 0) {
									const reservationIds = reservations.map((reservation) => reservation.id)
									return this._apiService
										.orderControllerFindOrdersByReservationIds(reservationIds)
										.pipe(map((orders) => ({ reservations, orders })))
								}
								return of({ reservations: [], orders: [] })
							}),
						)
					}
					return of({ reservations: [], orders: [] })
				}),
				tap(() => this.openOverlay()),
			)
			.subscribe({
				next: ({ reservations, orders }) => {
					this.reservations = reservations.map((reservation) => {
						const order = orders.find((order) => order.reservationId === reservation.id)
						const tables = this.tables.filter((table) => reservation.tableIds.includes(table.id))
						const tableNames = tables.map((table) => table.name)

						return { ref: reservation, state: reservation.state, tables, tableNames, order } as ReservationView
					})
				},
			})
	}

	checkin(tableIds: string[], reservationId: string): void {
		this._apiService
			.orderControllerCheckin({ tableIds, reservationId })
			.pipe(untilDestroyed(this))
			.subscribe({
				next: () => this.actionSuccessSubject.next(),
			})
	}

	confirm(reservationId: string): void {
		this._apiService
			.reservationControllerConfirmReservation(reservationId)
			.pipe(untilDestroyed(this))
			.subscribe({
				next: () => this.actionSuccessSubject.next(),
			})
	}

	goToReservation(reservation: ReservationResponse): void {
		this._router.navigate(['/reservations'], {
			queryParams: { id: reservation.id, layout: 'list', date: reservation.startDate },
		})
		this.closeOverlay()
	}

	private loadTables(): void {
		this._apiService
			.roomPlanControllerFindAllTables()
			.pipe(untilDestroyed(this))
			.subscribe({
				next: (tables) => (this.tables = tables),
			})
	}

	private openOverlay() {
		if (this.isOverlayOpen) return
		const position = this.createConnectedPositionStrategy(this.originElement())
		this.overlayRef = this._overlay.create({
			positionStrategy: position,
			hasBackdrop: true,
			backdropClass: 'bg-transparent',
		})

		const portal = new TemplatePortal(this.reservationsTemplate(), this.reservationsContainer())
		this.overlayRef.attach(portal)
		this.isOverlayOpen = true

		this.overlayRef.backdropClick().subscribe(() => this.closeOverlay())
	}

	private closeOverlay(): void {
		if (!this.overlayRef) return
		this.overlayRef.detach()
		this.overlayRef.dispose()
		this.isOverlayOpen = false
	}

	private createConnectedPositionStrategy(origin: ElementRef): FlexibleConnectedPositionStrategy {
		return this._overlay
			.position()
			.flexibleConnectedTo(origin)
			.withDefaultOffsetY(5)
			.withPositions([
				new ConnectionPositionPair({ originX: 'center', originY: 'bottom' }, { overlayX: 'center', overlayY: 'top' }),
			])
	}
}
