import { CdkDrag, CdkDragEnd, CdkDragHandle, CdkDropList } from '@angular/cdk/drag-drop'
import { AsyncPipe, NgClass, NgStyle } from '@angular/common'
import { Component, ElementRef, ViewEncapsulation, inject, viewChild } from '@angular/core'
import { Router, RouterLink, RouterOutlet } from '@angular/router'
import { TableCombinationResponse, TableResponse } from '@api-client/angular'
import { ResizeElementDirection, ResizeElementDirective, ResizeElementEvent } from '@frontend/shared'
import { TranslocoDirective } from '@jsverse/transloco'
import { UntilDestroy } from '@ngneat/until-destroy'
import { range } from 'es-toolkit'
import { Observable, tap } from 'rxjs'
import { TABLE_CONSTANTS } from '../../../core'
import { Coordinates } from '../../../shared'
import { CountOperation, RoomPlanSettingsStore, SettingsView } from './room-plan.store'
import { LucideChevronLeft, LucideGripVertical, LucideUser } from '@lucide/angular'

@UntilDestroy({ checkProperties: true })
@Component({
	selector: 'kadi-room-plan-settings',
	templateUrl: './room-plan-settings.component.html',
	styleUrls: ['./room-plan-settings.component.scss'],
	providers: [RoomPlanSettingsStore],
	encapsulation: ViewEncapsulation.None,
	imports: [
		TranslocoDirective,
		RouterLink,
		NgStyle,
		CdkDropList,
		NgClass,
		CdkDrag,
		CdkDragHandle,
		ResizeElementDirective,
		RouterOutlet,
		AsyncPipe,
		LucideChevronLeft,
		LucideUser,
		LucideGripVertical,
	],
})
export class RoomPlanSettingsComponent {
	private readonly _router = inject(Router)
	private readonly _store = inject(RoomPlanSettingsStore)
	readonly range = range

	readonly gridElement = viewChild.required<ElementRef<HTMLDivElement>>('gridElement')

	POINT_LENGTH = TABLE_CONSTANTS.TABLE_POINT_LENGTH
	CountOperationEnum = CountOperation
	ResizeElementDirection = ResizeElementDirection
	TableShape = TableResponse.ShapeEnum
	SettingsView = SettingsView

	vm$: Observable<{
		tables: TableResponse[]
		selectedTable?: TableResponse
		selectedCombination?: TableCombinationResponse
		coordinates: Coordinates
		isScreenSmall: boolean
		activeView: SettingsView
	}>

	constructor() {
		this.vm$ = this._store
			.select({
				tables: this._store.tables$,
				selectedTable: this._store.selectedTable$,
				selectedCombination: this._store.selectedCombination$,
				coordinates: this._store.coordinates$,
				isScreenSmall: this._store.isScreenSmall$,
				activeView: this._store.activeView$,
			})
			.pipe(
				tap(({ isScreenSmall }) => {
					if (!isScreenSmall) this._router.navigateByUrl('/settings/room-plan/details')
				}),
			)
	}

	selectTable(index: number): void {
		this._store.selectTable(index)
	}

	onResize(event: ResizeElementEvent): void {
		const element = event.target as HTMLElement
		element.style.width = event.currentWidthValue + 'px'
		element.style.height = event.currentHeightValue + 'px'
	}

	stopResize(event: ResizeElementEvent, index: number): void {
		const width = Math.round(event.currentWidthValue / this.POINT_LENGTH)
		const height = Math.round(event.currentHeightValue / this.POINT_LENGTH)

		// Reset element width and height set by directive
		if (event.target instanceof HTMLElement) {
			event.target.style.width = ''
			event.target.style.height = ''
		}

		this._store.updateTableSize(width, height, index)
	}

	onDragEnd(event: CdkDragEnd, index: number): void {
		const element = event.source.element
		if (!element) return

		const rect = this.gridElement().nativeElement.getBoundingClientRect()
		const xDistance = event.dropPoint.x - rect.x
		const yDistance = event.dropPoint.y - rect.y

		const columnStart = Math.max(Math.floor(xDistance / this.POINT_LENGTH), 0)
		const rowStart = Math.max(Math.floor(yDistance / this.POINT_LENGTH), 0)

		this._store.updateTableCoordinates(columnStart, rowStart, index)
	}

	existsInCombination(tableId: string, combination?: TableCombinationResponse): boolean {
		return combination?.tableIds.includes(tableId) ?? false
	}
}
