import { Component, effect, inject, input } from '@angular/core'
import { NonNullableFormBuilder, ReactiveFormsModule, Validators } from '@angular/forms'
import { AnyType, SpecialDaysSchedule } from '@core/types'
import { TimeUtils } from '@core/utils'
import { SpecialDay, TimingRule } from '@api-client/angular'
import { TranslocoDirective } from '@jsverse/transloco'
import { range } from 'es-toolkit'
import { tail } from 'es-toolkit/compat'
import { SettingsStore } from '../../../../+state'
import { FormUtils } from '../../../../shared'
import { LucidePlus, LucideTrash, LucideX } from '@lucide/angular'

@Component({
	selector: 'kadi-special-days-settings',
	templateUrl: './special-days-settings.component.html',
	styleUrls: ['./special-days-settings.component.scss'],
	imports: [TranslocoDirective, ReactiveFormsModule, LucideTrash, LucidePlus, LucideX],
})
export class SpecialDaysSettingsComponent {
	private readonly _formBuilder = inject(NonNullableFormBuilder)
	private readonly _settingsStore = inject(SettingsStore)
	readonly range = range

	schedule = input<SpecialDaysSchedule | undefined>()

	form = this._formBuilder.group({
		schedule: this._formBuilder.array<ReturnType<typeof this.getDayFormRow>>([]),
	})

	constructor() {
		effect(() => {
			const schedule = this.schedule()
			if (!schedule) return

			for (const [scheduleIndex, day] of schedule.entries()) {
				this.addRow(day)

				if (day.rules)
					for (const [index, rule] of day.rules.entries()) {
						// HTML time input only supports string values, so we convert time to string value
						if (rule.closingTime)
							(rule as AnyType).closingTime = TimeUtils.formatAsString(
								TimeUtils.utcToLocal(rule.closingTime, this._settingsStore.timezone()),
							)
						if (rule.openingTime)
							(rule as AnyType).openingTime = TimeUtils.formatAsString(
								TimeUtils.utcToLocal(rule.openingTime, this._settingsStore.timezone()),
							)

						if (index === 0) continue

						this.addRulesRow(scheduleIndex, rule)
					}

				if (day.closed) this.onClosedChange(true, scheduleIndex)
			}

			FormUtils.updateandValidate(this.form.controls.schedule, schedule)
		})
	}

	get scheduleControl() {
		return this.form.controls.schedule
	}

	get maxRulesControls(): number {
		return Math.max(
			...this.scheduleControl.controls.map((_control, index) => this.getRulesControls(index).controls.length),
		)
	}

	getSingleScheduleControl(index: number) {
		return this.scheduleControl.controls.at(index)
	}

	addRow(day?: SpecialDay): void {
		const control = this.getDayFormRow(day)
		this.scheduleControl.push(control)
	}

	removeRow(index: number): void {
		this.scheduleControl.removeAt(index)
	}

	onClosedChange(checked: boolean, index: number): void {
		const rulesControls = this.getRulesControls(index)

		if (checked) {
			// Remove all controls expect first
			for (const [index] of tail(rulesControls.controls).entries()) {
				rulesControls.removeAt(index)
			}

			rulesControls.at(0)?.controls.openingTime.setValue(undefined)
			rulesControls.at(0)?.controls.openingTime.disable()
			rulesControls.at(0)?.controls.closingTime.setValue(undefined)
			rulesControls.at(0)?.controls.closingTime.disable()
		} else {
			rulesControls.at(0)?.controls.openingTime.enable()
			rulesControls.at(0)?.controls.closingTime.enable()
		}

		this.form.updateValueAndValidity()
	}

	getRulesControls(scheduleIndex: number) {
		return this.scheduleControl.at(scheduleIndex).controls.rules
	}

	addRulesRow(scheduleIndex: number, rule?: TimingRule): void {
		const rulesControl = this.getRulesControls(scheduleIndex)
		rulesControl.push(this.getRulesFormRow(rule))
	}

	removeRulesRow(index: number, scheduleIndex: number) {
		const rulesControl = this.getRulesControls(scheduleIndex)
		rulesControl.removeAt(index)
	}

	private getDayFormRow(day?: SpecialDay) {
		return this._formBuilder.group({
			date: [day?.date ?? undefined, Validators.required],
			recurring: [day?.recurring ?? false],
			rules: this._formBuilder.array([this.getRulesFormRow()]),
			closed: [day?.closed ?? false],
		})
	}

	private getRulesFormRow(rule?: TimingRule) {
		return this._formBuilder.group({
			openingTime: this._formBuilder.control(rule?.openingTime ?? undefined, Validators.required),
			closingTime: this._formBuilder.control(rule?.closingTime ?? undefined, Validators.required),
		})
	}
}
