import { AsyncPipe, CurrencyPipe, KeyValuePipe, NgClass } from '@angular/common'
import { Component, inject } from '@angular/core'
import {
	MenuItemResponse,
	OrderItemResponse,
	OrderResponse,
	PayOrderItemRequest,
	SettingsResponse,
} from '@api-client/angular'
import { FeatureKey } from '@core/types'
import { isFeatureEnabled } from '@core/utils'
import { GroupByPipe, LoadingButtonDirective, SwipeActionsModule } from '@frontend/shared'
import { TranslocoDirective } from '@jsverse/transloco'
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'
import { uniq } from 'es-toolkit/compat'
import { finalize, map, Observable, take, tap } from 'rxjs'
import { DashboardStore } from '../dashboard.store'
import { ItemStatePipe } from '../pipes/item-state.pipe'
import { DashboardTable } from '../types'
import { OrderMenuViewComponent } from './menu/menu.component'
import { LucideCheck, LucideCirclePlus, LucideCookingPot, LucideUtensilsCrossed } from '@lucide/angular'

type BillType = 'PayAll' | 'Split'
type ViewType = 'Order' | 'Menu'

@UntilDestroy({ checkProperties: true })
@Component({
	selector: 'kadi-order',
	templateUrl: './order.component.html',
	styleUrls: ['./order.component.scss'],
	imports: [
		TranslocoDirective,
		SwipeActionsModule,
		NgClass,
		OrderMenuViewComponent,
		LoadingButtonDirective,
		AsyncPipe,
		CurrencyPipe,
		KeyValuePipe,
		GroupByPipe,
		ItemStatePipe,
		LucideCookingPot,
		LucideUtensilsCrossed,
		LucideCheck,
		LucideCirclePlus,
	],
})
export class OrderComponent {
	table$: Observable<DashboardTable>
	menuItems$: Observable<MenuItemResponse[]>
	loading = false
	// Items that are selected for payment in split view mode
	selectedItems: Array<OrderItemResponse & { selectedQuantity: number }> = []
	selectedBillType: BillType = 'PayAll'
	selectedViewType: ViewType = 'Order'
	courses: number[] = []
	tableCookingState: OrderItemResponse.StateEnum | undefined = undefined
	OrderItemState = OrderItemResponse.StateEnum
	settings: SettingsResponse | undefined
	isFeatureEnabled = isFeatureEnabled
	FeatureKey = FeatureKey
	private readonly _store = inject(DashboardStore)

	constructor() {
		this.loadSettings()

		this.table$ = this._store.selectedTable$.pipe(
			map((table) => table as DashboardTable),
			tap((table) => {
				if (!table.order) {
					this.openNotificationsView()
					return
				}
				this.courses = uniq(
					table.order.items.filter((item) => !!item.course).map((item) => item.course as number),
				).sort((a, b) => a - b)
				this.tableCookingState = this.getOrderCookingState(table.order)
			}),
			map((table) => {
				if (!table.order) return table
				table.order.items = table.order.items
					.sort((aItem, bItem) => Number(aItem.quantity > bItem.quantity ? -1 : 1))
					.sort((aItem, bItem) => Number(aItem.paid) - Number(bItem.paid))
				return table
			}),
		)

		this.menuItems$ = this._store.select(({ menuItems }) => menuItems)
	}

	pay(order: OrderResponse): void {
		this.loading = true
		const items: PayOrderItemRequest[] =
			this.selectedBillType === 'Split'
				? this.selectedItems.map((item) => ({ id: item.id, quantity: item.selectedQuantity }))
				: order.items
						.filter((_item) => !_item.paid)
						.map((item) => ({ id: item.id, quantity: item.quantity - item.paidQuantity }))

		this._store
			.payItems(order.id, items)
			.pipe(
				untilDestroyed(this),
				finalize(() => (this.loading = false)),
			)
			.subscribe({
				next: () => {
					this.selectedItems = []
				},
			})
	}

	openNotificationsView(): void {
		this._store.openNotifications()
	}

	isSelected(itemId: string): boolean {
		return this.selectedItems.some((item) => item.menuItemId === itemId)
	}

	selectedQuantity(id: string): number {
		return this.selectedItems.find((item) => item.id === id)?.selectedQuantity ?? 0
	}

	decrement(item: OrderItemResponse): void {
		const index = this.selectedItems.findIndex((_item) => _item.id === item.id)
		if (index === -1) return

		const existingItem = this.selectedItems[index]
		if (existingItem.selectedQuantity === 0) return

		this.selectedItems[index] = {
			...item,
			selectedQuantity: existingItem.selectedQuantity - 1,
		}
	}

	increment(item: OrderItemResponse): void {
		const index = this.selectedItems.findIndex((_item) => _item.id === item.id)
		if (index === -1) this.selectedItems.push({ ...item, selectedQuantity: 1 })
		else {
			const existingItem = this.selectedItems[index]
			if (existingItem.selectedQuantity === existingItem.quantity - existingItem.paidQuantity) return
			this.selectedItems[index] = {
				...existingItem,
				selectedQuantity: existingItem.selectedQuantity + 1,
			}
		}
	}

	addToCourse(orderId: string, itemId: string, course: number): void {
		this._store.updateItemCouse(orderId, itemId, course)
	}

	updateItemsState(items: OrderItemResponse[], state: OrderItemResponse.StateEnum) {
		this.table$.pipe(untilDestroyed(this), take(1)).subscribe({
			next: ({ order }) => {
				if (!order) return
				this._store.updateItemsState(order.id, items, state)
			},
		})
	}

	placeOrder(orderId: string): void {
		this.loading = true

		this._store
			.addOrderItemsFromCart(orderId)
			.pipe(
				untilDestroyed(this),
				finalize(() => (this.loading = false)),
			)
			.subscribe({
				next: () => {
					this.selectedViewType = 'Order'
				},
			})
	}

	private getOrderCookingState(order: OrderResponse): OrderItemResponse.StateEnum | undefined {
		// If all items are not same state, do not assign a status
		if (order.items.length === 0 || uniq(order.items.map((item) => item.state)).length > 1) {
			return undefined
		}
		return order.items[0].state
	}

	private loadSettings(): void {
		this._store.settings$.pipe(untilDestroyed(this)).subscribe((settings) => (this.settings = settings))
	}
}
