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

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

	schedule = input.required<WeeklySchedule | undefined>()

	constructor() {
		effect(() => {
			const schedule = this.schedule()

			if (schedule) {
				for (const day of Object.keys(schedule)) {
					const dayRules = schedule[day as WeekDay]
					if (!dayRules) continue

					// eslint-disable-next-line unicorn-x/no-array-for-each
					dayRules.rules?.forEach((rule, index) => {
						// HTML time input only supports string values, so we convert time to string value
						/* eslint-disable @typescript-eslint/no-explicit-any */
						if (rule.closingTime)
							(rule as any).closingTime = TimeUtils.formatAsString(
								TimeUtils.utcToLocal(rule.closingTime, this._settingsStore.timezone()),
							)
						if (rule.openingTime)
							(rule as any).openingTime = TimeUtils.formatAsString(
								TimeUtils.utcToLocal(rule.openingTime, this._settingsStore.timezone()),
							)
						/* eslint-enable @typescript-eslint/no-explicit-any */

						// Remove the default first row
						if (index === 0) this.removeRow(day, 0)
						this.addRow(day, rule)
					})

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

				FormUtils.updateandValidate(this.form.get('schedule') as UntypedFormGroup, schedule)
			}
		})
	}

	form = this._formBuilder.group({
		schedule: this._formBuilder.group({
			[WeekDay.Monday]: this.getDayFromGroup(),
			[WeekDay.Tuesday]: this.getDayFromGroup(),
			[WeekDay.Wednesday]: this.getDayFromGroup(),
			[WeekDay.Thursday]: this.getDayFromGroup(),
			[WeekDay.Friday]: this.getDayFromGroup(),
			[WeekDay.Saturday]: this.getDayFromGroup(),
			[WeekDay.Sunday]: this.getDayFromGroup(),
		}),
	})

	get days(): string[] {
		return Object.keys(WeekDay)
	}

	get maxRulesControls(): number {
		return Math.max(...this.days.map((day) => this.getRulesControl(day).controls.length))
	}

	getRulesControl(day: string) {
		return this.form.controls.schedule.controls[day as WeekDay].controls.rules
	}

	isDayClosed(day: string): boolean {
		return this.form.controls.schedule.controls[day as WeekDay].value.closed ?? false
	}

	onClosedChange(isClosed: boolean, day: string): void {
		const rulesControl = this.getRulesControl(day)

		if (isClosed) {
			// Remove all controls expect first
			for (let i = rulesControl.controls.length; i-- > 1; ) {
				rulesControl.removeAt(i)
			}

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

		this.form.updateValueAndValidity()
	}

	addRow(day: string, rule?: TimingRule) {
		const rulesControl = this.getRulesControl(day)
		rulesControl.push(this.getRulesFormGroup(rule))
	}

	removeRow(day: string, index: number) {
		const rulesControl = this.getRulesControl(day)
		rulesControl.removeAt(index)
	}

	private getDayFromGroup() {
		return this._formBuilder.group({
			closed: this._formBuilder.control(false),
			rules: this._formBuilder.array([this.getRulesFormGroup()]),
		})
	}

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