var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { MelodicComponent } from '@melodicdev/core';
import { computePosition, autoUpdate, offset, flip, shift } from '../../../utils/positioning/index.js';
import { timePickerTemplate } from './time-picker.template.js';
import { timePickerStyles } from './time-picker.styles.js';
function pad(n) {
    return String(n).padStart(2, '0');
}
function formatDisplay(value, use12Hour) {
    if (!value)
        return '';
    const parts = value.split(':');
    if (parts.length < 2)
        return value;
    let h = parseInt(parts[0], 10);
    const m = parts[1];
    const s = parts[2];
    const timeSuffix = s ? `:${s}` : '';
    if (!use12Hour)
        return `${pad(h)}:${m}${timeSuffix}`;
    const period = h >= 12 ? 'PM' : 'AM';
    if (h === 0)
        h = 12;
    else if (h > 12)
        h -= 12;
    return `${h}:${m}${timeSuffix} ${period}`;
}
function clamp(val, min, max) {
    if (val < min)
        return max;
    if (val > max)
        return min;
    return val;
}
/**
 * ml-time-picker - Time input with dropdown selector
 *
 * @example
 * ```html
 * <ml-time-picker label="Start time" value="09:30"></ml-time-picker>
 * <ml-time-picker label="Meeting" use-12-hour value="14:00"></ml-time-picker>
 * <ml-time-picker label="Precise" step="1"></ml-time-picker>
 * ```
 *
 * @fires ml:change - Emitted when the time changes. Detail: { value: string }
 */
let TimePickerComponent = class TimePickerComponent {
    constructor() {
        /** Selected time in HH:mm or HH:mm:ss format */
        this.value = '';
        /** Placeholder text */
        this.placeholder = 'Select time';
        /** Field label */
        this.label = '';
        /** Hint text */
        this.hint = '';
        /** Error message */
        this.error = '';
        /** Input size */
        this.size = 'md';
        /** Disabled state */
        this.disabled = false;
        /** Required state */
        this.required = false;
        /** Minimum selectable time (HH:mm) */
        this.min = '';
        /** Maximum selectable time (HH:mm) */
        this.max = '';
        /** Step in minutes (default 15) for the preset list. Use 1 to show seconds spinner. */
        this.step = 15;
        /** Use 12-hour format with AM/PM (default: true) */
        this.twelveHour = true;
        /** Whether the popover is open */
        this.isOpen = false;
        /** Current editing hour */
        this.editHour = 0;
        /** Current editing minute */
        this.editMinute = 0;
        /** Current editing second */
        this.editSecond = 0;
        /** AM or PM when in 12-hour mode */
        this.editPeriod = 'AM';
        this._cleanupAutoUpdate = null;
        this.togglePopover = () => {
            if (this.disabled)
                return;
            const popoverEl = this.getPopoverEl();
            if (popoverEl) {
                popoverEl.togglePopover();
            }
        };
        this.incrementHour = () => {
            if (this.use12Hour) {
                // Cycle within the current 12-hour half (AM: 0–11, PM: 12–23)
                const base = this.editPeriod === 'AM' ? 0 : 12;
                const offset = (this.editHour - base + 1) % 12;
                this.editHour = base + offset;
            }
            else {
                this.editHour = clamp(this.editHour + 1, 0, 23);
            }
        };
        this.decrementHour = () => {
            if (this.use12Hour) {
                const base = this.editPeriod === 'AM' ? 0 : 12;
                const offset = (this.editHour - base - 1 + 12) % 12;
                this.editHour = base + offset;
            }
            else {
                this.editHour = clamp(this.editHour - 1, 0, 23);
            }
        };
        this.incrementMinute = () => {
            this.editMinute = clamp(this.editMinute + 1, 0, 59);
        };
        this.decrementMinute = () => {
            this.editMinute = clamp(this.editMinute - 1, 0, 59);
        };
        this.incrementSecond = () => {
            this.editSecond = clamp(this.editSecond + 1, 0, 59);
        };
        this.decrementSecond = () => {
            this.editSecond = clamp(this.editSecond - 1, 0, 59);
        };
        this.togglePeriod = () => {
            this.editPeriod = this.editPeriod === 'AM' ? 'PM' : 'AM';
            const h12 = this.editHour % 12 || 12;
            this.editHour = this.to24Hour(h12, this.editPeriod);
        };
        this.confirmSelection = () => {
            let timeStr = `${pad(this.editHour)}:${pad(this.editMinute)}`;
            if (this.showSeconds) {
                timeStr += `:${pad(this.editSecond)}`;
            }
            this.commitValue(timeStr);
            this.closePopover();
        };
        this.handleNowClick = () => {
            const now = new Date();
            this.editHour = now.getHours();
            this.editMinute = now.getMinutes();
            this.editSecond = now.getSeconds();
            this.editPeriod = this.editHour >= 12 ? 'PM' : 'AM';
        };
        this.handleKeyDown = (event) => {
            if (event.key === 'Escape' && this.isOpen) {
                event.preventDefault();
                this.closePopover();
            }
            else if ((event.key === 'Enter' || event.key === ' ' || event.key === 'ArrowDown') && !this.isOpen) {
                event.preventDefault();
                this.togglePopover();
            }
        };
        this.handleHourInput = (event) => {
            const input = event.target;
            const digits = input.value.replace(/\D/g, '').slice(0, 2);
            if (digits === '') {
                input.value = '';
                return;
            }
            const max = this.use12Hour ? 12 : 23;
            const min = this.use12Hour ? 1 : 0;
            const n = Math.max(min, Math.min(parseInt(digits, 10), max));
            input.value = String(n);
            if (this.use12Hour) {
                this.editHour = this.to24Hour(n, this.editPeriod);
            }
            else {
                this.editHour = n;
            }
        };
        this.handleMinuteInput = (event) => {
            const input = event.target;
            const digits = input.value.replace(/\D/g, '').slice(0, 2);
            if (digits === '') {
                input.value = '';
                return;
            }
            const n = Math.min(parseInt(digits, 10), 59);
            input.value = String(n);
            this.editMinute = n;
        };
        this.handleSecondInput = (event) => {
            const input = event.target;
            const digits = input.value.replace(/\D/g, '').slice(0, 2);
            if (digits === '') {
                input.value = '';
                return;
            }
            const n = Math.min(parseInt(digits, 10), 59);
            input.value = String(n);
            this.editSecond = n;
        };
        this.handleHourBlur = () => {
            if (this.use12Hour) {
                const h12 = this.editHour % 12 || 12;
                this.editHour = this.to24Hour(h12, this.editPeriod);
            }
        };
        this.handleMinuteBlur = () => {
            // Re-render to reformat with padding
        };
        this.handleSecondBlur = () => {
            // Re-render to reformat with padding
        };
        this.handleInputFocus = (event) => {
            event.target.select();
        };
        this.handleSpinnerKeyDown = (event) => {
            const target = event.target;
            if (event.key === 'ArrowUp') {
                event.preventDefault();
                const label = target.getAttribute('aria-label');
                if (label === 'Hour')
                    this.incrementHour();
                else if (label === 'Minute')
                    this.incrementMinute();
                else if (label === 'Second')
                    this.incrementSecond();
            }
            else if (event.key === 'ArrowDown') {
                event.preventDefault();
                const label = target.getAttribute('aria-label');
                if (label === 'Hour')
                    this.decrementHour();
                else if (label === 'Minute')
                    this.decrementMinute();
                else if (label === 'Second')
                    this.decrementSecond();
            }
            else if (event.key === 'Enter') {
                event.preventDefault();
                this.confirmSelection();
            }
        };
        this._handleToggle = (event) => {
            const toggleEvent = event;
            if (toggleEvent.newState === 'open') {
                this.isOpen = true;
                this.syncEditFromValue();
                this.startPositioning();
            }
            else {
                this.isOpen = false;
                this._cleanupAutoUpdate?.();
                this._cleanupAutoUpdate = null;
                this.returnFocus();
            }
        };
    }
    get use12Hour() {
        return this.twelveHour;
    }
    get showSeconds() {
        return Number(this.step) === 1;
    }
    get displayValue() {
        return formatDisplay(this.value, this.use12Hour);
    }
    get displayHour() {
        if (this.use12Hour) {
            let h = this.editHour;
            if (h === 0)
                h = 12;
            else if (h > 12)
                h -= 12;
            return String(h);
        }
        return pad(this.editHour);
    }
    get displayMinute() {
        return pad(this.editMinute);
    }
    get displaySecond() {
        return pad(this.editSecond);
    }
    onCreate() {
        const popoverEl = this.getPopoverEl();
        if (popoverEl) {
            popoverEl.addEventListener('toggle', this._handleToggle);
        }
    }
    onDestroy() {
        this._cleanupAutoUpdate?.();
        const popoverEl = this.getPopoverEl();
        if (popoverEl) {
            popoverEl.removeEventListener('toggle', this._handleToggle);
        }
    }
    to24Hour(h12, period) {
        if (period === 'AM')
            return h12 === 12 ? 0 : h12;
        return h12 === 12 ? 12 : h12 + 12;
    }
    syncEditFromValue() {
        if (this.value) {
            const parts = this.value.split(':');
            this.editHour = parseInt(parts[0], 10) || 0;
            this.editMinute = parseInt(parts[1], 10) || 0;
            this.editSecond = parts[2] ? parseInt(parts[2], 10) : 0;
        }
        else {
            const now = new Date();
            this.editHour = now.getHours();
            this.editMinute = now.getMinutes();
            this.editSecond = 0;
        }
        this.editPeriod = this.editHour >= 12 ? 'PM' : 'AM';
    }
    commitValue(timeStr) {
        this.value = timeStr;
        this.elementRef.dispatchEvent(new CustomEvent('ml:change', {
            bubbles: true,
            composed: true,
            detail: { value: timeStr }
        }));
    }
    closePopover() {
        const popoverEl = this.getPopoverEl();
        if (popoverEl && this.isOpen) {
            popoverEl.hidePopover();
        }
    }
    startPositioning() {
        const triggerEl = this.getTriggerEl();
        const popoverEl = this.getPopoverEl();
        if (!triggerEl || !popoverEl)
            return;
        const update = () => this.updatePosition(triggerEl, popoverEl);
        this._cleanupAutoUpdate?.();
        this._cleanupAutoUpdate = autoUpdate(triggerEl, popoverEl, update);
    }
    updatePosition(triggerEl, popoverEl) {
        const middleware = [offset(4), flip(), shift({ padding: 8 })];
        const { x, y } = computePosition(triggerEl, popoverEl, {
            placement: 'bottom-start',
            middleware
        });
        popoverEl.style.left = `${x}px`;
        popoverEl.style.top = `${y}px`;
    }
    returnFocus() {
        const triggerEl = this.getTriggerEl();
        if (triggerEl) {
            triggerEl.focus();
        }
    }
    getTriggerEl() {
        return this.elementRef.shadowRoot?.querySelector('.ml-time-picker__trigger');
    }
    getPopoverEl() {
        return this.elementRef.shadowRoot?.querySelector('.ml-time-picker__popover');
    }
};
TimePickerComponent = __decorate([
    MelodicComponent({
        selector: 'ml-time-picker',
        template: timePickerTemplate,
        styles: timePickerStyles,
        attributes: ['value', 'placeholder', 'label', 'hint', 'error', 'size', 'disabled', 'required', 'min', 'max', 'step', 'twelve-hour']
    })
], TimePickerComponent);
export { TimePickerComponent };
