import { property, state, query } from 'lit/decorators.js'
import { html } from 'lit'
import { createRef, ref } from 'lit/directives/ref.js'
import componentStyles from '../../styles/component.styles.js'
import TerraElement from '../../internal/terra-element.js'
import styles from './date-picker.styles.js'
import type { CSSResultGroup } from 'lit'
import TerraButton from '../button/button.component.js'
import TerraInput from '../input/input.component.js'
import TerraDropdown from '../dropdown/dropdown.component.js'
import { isValid } from 'date-fns'

interface DateRange {
    startDate: Date | null
    endDate: Date | null
}

interface PresetRange {
    label: string
    getValue: () => DateRange
}

/**
 * @summary A date picker component that implements the Horizon Design System (HDS) Date Picker patterns. Supports single date selection or date range selection with calendar popup.
 * @documentation https://terra-ui.netlify.app/components/date-picker
 * @status stable
 * @since 1.0
 *
 * @dependency terra-input
 * @dependency terra-button
 * @dependency terra-dropdown
 *
 * @slot - The default slot.
 *
 * @event terra-date-range-change - Emitted when a date selection is made or changed.
 * @eventDetail { startDate: string, endDate: string } - ISO date strings or YYYY-MM-DD format.
 *
 * @csspart base - The component's base wrapper.
 * @csspart input - The date input element (terra-input).
 * @csspart calendar - The calendar dropdown.
 * @csspart sidebar - The preset ranges sidebar.
 *
 * @cssproperty --terra-date-picker-* - All date picker design tokens from horizon.css are supported.
 */
export default class TerraDatePicker extends TerraElement {
    static styles: CSSResultGroup = [componentStyles, styles]
    static dependencies = {
        'terra-button': TerraButton,
        'terra-input': TerraInput,
        'terra-dropdown': TerraDropdown,
    }

    @property() id: string
    @property({ type: Boolean, reflect: true }) range = false
    @property({ attribute: 'min-date', reflect: true }) minDate?: string
    @property({ attribute: 'max-date', reflect: true }) maxDate?: string
    @property({ attribute: 'start-date', reflect: true }) startDate?: string
    @property({ attribute: 'end-date', reflect: true }) endDate?: string
    @property({ attribute: 'hide-label', type: Boolean }) hideLabel = false
    @property() label: string = 'Select Date'
    @property({ attribute: 'help-text' }) helpText = ''
    @property({ attribute: 'start-help-text' }) startHelpText = ''
    @property({ attribute: 'end-help-text' }) endHelpText = ''
    @property({ attribute: 'start-label' }) startLabel?: string
    @property({ attribute: 'end-label' }) endLabel?: string
    @property({ type: Boolean, attribute: 'show-presets' }) showPresets = false
    @property({ type: Array }) presets: PresetRange[] = []
    @property({ type: Boolean, attribute: 'enable-time' }) enableTime = false
    @property({ attribute: 'display-format' }) displayFormat?: string
    @property({ type: Boolean }) inline = false
    @property({ type: Boolean, attribute: 'split-inputs' }) splitInputs = false
    @property() placeholder: string = 'Select Date'
    @property() startPlaceholder: string = 'Start Date'
    @property() endPlaceholder: string = 'End Date'
    /** The ARIA role for the button. Defaults to 'group'. */
    @property({ reflect: true }) role: string | null = 'group'
    /** The ARIA label for the date picker. Defaults to 'Date picker'.*/
    @property({ reflect: true, attribute: 'aria-label' }) ariaLabel: string | null =
        'Date picker'
    @property({ type: Boolean }) hideClearAll = false
    @property() clearAllLabel: string = 'Clear Dates'

    @state() isOpen = false
    @state() leftMonth: Date = new Date()
    @state() rightMonth: Date = new Date()
    @state() selectedStart: Date | null = null
    @state() selectedEnd: Date | null = null
    @state() hoverDate: Date | null = null
    @state() isSelectingRange = false
    @state() showLeftMonthDropdown = false
    @state() showRightMonthDropdown = false
    @state() startHour: number = 0
    @state() startMinute: number = 0
    @state() startSecond: number = 0
    @state() endHour: number = 23
    @state() endMinute: number = 59
    @state() endSecond: number = 59

    @state() selectedDates = {
        startDate: new Date().toString(),
        endDate: new Date().toString(),
    }

    @query('.date-picker__dropdown') dropdown: HTMLElement
    dropdownRef = createRef<TerraDropdown>()

    private readonly DAYS = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa']
    private readonly MONTHS = [
        'January',
        'February',
        'March',
        'April',
        'May',
        'June',
        'July',
        'August',
        'September',
        'October',
        'November',
        'December',
    ]

    constructor() {
        super()
        this.initializePresets()
    }

    /**
     * Parse a date string (YYYY-MM-DD or ISO datetime) as a local date, avoiding timezone issues.
     * When you do `new Date("2024-03-20")`, JavaScript interprets it as UTC midnight,
     * which can cause off-by-one day errors when using getDate() in local timezone.
     * This function parses the date as a local date instead.
     *
     * When enableTime is true, datetime strings are parsed as UTC to match API min/max dates.
     */
    private parseLocalDate(dateString: string): Date {
        // Check if it's a date-only string (YYYY-MM-DD format)
        const dateOnlyPattern = /^\d{4}-\d{2}-\d{2}$/
        if (dateOnlyPattern.test(dateString)) {
            const [year, month, day] = dateString.split('-').map(Number)
            // When time is enabled, parse date-only strings as UTC midnight
            // to match how datetime strings and min/max dates from APIs are handled
            if (this.enableTime) {
                return new Date(Date.UTC(year, month - 1, day, 0, 0, 0))
            }
            // When time is not enabled, parse as local midnight
            return new Date(year, month - 1, day)
        }

        // Check if it's a datetime string in format (YYYY-MM-DDTHH:mm:ss)
        const dateTimePattern = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$/
        if (dateTimePattern.test(dateString)) {
            const [datePart, timePart] = dateString.split('T')
            const [year, month, day] = datePart.split('-').map(Number)
            const [hours, minutes, seconds] = timePart.split(':').map(Number)
            // When time is enabled, parse as UTC to match API's UTC min/max dates
            return new Date(Date.UTC(year, month - 1, day, hours, minutes, seconds))
        }

        // For ISO strings with time (including UTC 'Z' suffix), use standard Date parsing
        return new Date(dateString)
    }

    /**
     * Check if two dates are in the same calendar month and year
     */
    private isSameMonth(date1: Date, date2: Date): boolean {
        if (this.enableTime) {
            return (
                date1.getUTCFullYear() === date2.getUTCFullYear() &&
                date1.getUTCMonth() === date2.getUTCMonth()
            )
        }
        return (
            date1.getFullYear() === date2.getFullYear() &&
            date1.getMonth() === date2.getMonth()
        )
    }

    /**
     * Check if a date's month/year matches a given month Date
     */
    private isDateInMonth(date: Date, monthDate: Date): boolean {
        if (this.enableTime) {
            return (
                date.getUTCFullYear() === monthDate.getUTCFullYear() &&
                date.getUTCMonth() === monthDate.getUTCMonth()
            )
        }
        return (
            date.getFullYear() === monthDate.getFullYear() &&
            date.getMonth() === monthDate.getMonth()
        )
    }

    private getBounds(): { min?: Date; max?: Date } {
        const min = this.minDate ? this.parseLocalDate(this.minDate) : undefined
        const max = this.maxDate ? this.parseLocalDate(this.maxDate) : undefined
        return { min, max }
    }

    private doesRangeOverlapBounds(range: DateRange): boolean {
        const { startDate, endDate } = range
        const { min, max } = this.getBounds()

        if (!this.range) {
            if (!startDate) return false
            if (min && startDate < min) return false
            if (max && startDate > max) return false
            return true
        }

        const start = startDate ?? new Date(-8640000000000000)
        const end = endDate ?? new Date(8640000000000000)

        if (!min && !max) return true
        const windowStart = min ?? new Date(-8640000000000000)
        const windowEnd = max ?? new Date(8640000000000000)
        return end >= windowStart && start <= windowEnd
    }

    private isPresetWithinBounds(range: DateRange): boolean {
        return this.doesRangeOverlapBounds(range)
    }

    private get filteredPresets(): PresetRange[] {
        return (this.presets || []).filter(preset =>
            this.isPresetWithinBounds(preset.getValue())
        )
    }

    open() {
        this.isOpen = true

        // If a max date is provided and no explicit selection exists,
        // open the calendar to the max date's month (right calendar in range mode)
        if (this.maxDate && !this.selectedStart && !this.selectedEnd) {
            const max = this.parseLocalDate(this.maxDate)
            if (!isNaN(max.getTime())) {
                if (this.range) {
                    this.rightMonth = new Date(max)
                    const left = new Date(max)
                    left.setMonth(left.getMonth() - 1)
                    this.leftMonth = left
                } else {
                    this.leftMonth = new Date(max)
                }
            }
        }

        // Open the dropdown if not inline
        if (!this.inline && this.dropdownRef.value) {
            this.dropdownRef.value.show()
        }

        this.requestUpdate()
    }

    close() {
        this.isOpen = false
        // Close the dropdown if not inline
        if (!this.inline && this.dropdownRef.value) {
            this.dropdownRef.value.hide()
        }
        this.requestUpdate()
    }

    /**
     * Clears the selected date(s) and resets the date picker to its initial state.
     */
    clear() {
        this.selectedStart = null
        this.selectedEnd = null
        this.hoverDate = null
        this.isSelectingRange = false

        // Reset time to defaults
        this.startHour = 0
        this.startMinute = 0
        this.startSecond = 0
        this.endHour = 23
        this.endMinute = 59
        this.endSecond = 59

        this.clearInputValidation()

        this.requestUpdate()

        this.emitChange()
    }

    setOpen(open: boolean) {
        if (open) {
            this.open()
        } else {
            this.close()
        }
    }

    willUpdate(changedProperties: Map<PropertyKey, unknown>) {
        super.willUpdate(changedProperties)

        // Handle inline property changes
        if (changedProperties.has('inline')) {
            if (this.inline) {
                this.isOpen = true
                // Close dropdown when switching to inline mode
                if (this.dropdownRef.value) {
                    this.dropdownRef.value.hide()
                }
            }
        }

        // Handle minDate/maxDate changes
        if (changedProperties.has('minDate') || changedProperties.has('maxDate')) {
            // When minDate or maxDate changes (e.g., from async API call),
            // update calendar view to show the maxDate if no selection exists yet
            if (this.maxDate && !this.selectedStart && !this.selectedEnd) {
                const max = this.parseLocalDate(this.maxDate)
                if (!isNaN(max.getTime())) {
                    if (this.range) {
                        this.rightMonth = new Date(max)
                        const left = new Date(max)
                        left.setMonth(left.getMonth() - 1)
                        this.leftMonth = left
                    } else {
                        this.leftMonth = new Date(max)
                    }
                }
            }
        }

        // Handle startDate/endDate changes
        if (changedProperties.has('startDate') || changedProperties.has('endDate')) {
            // Sync internal state with props when they change
            if (this.startDate) {
                const start = this.parseLocalDate(this.startDate)
                if (!isNaN(start.getTime())) {
                    this.selectedStart = start
                    if (this.enableTime) {
                        this.initializeTimeFromDate(start, true)
                    }
                }
            } else {
                this.selectedStart = null
            }

            if (this.range) {
                if (this.endDate) {
                    const end = this.parseLocalDate(this.endDate)
                    if (!isNaN(end.getTime())) {
                        this.selectedEnd = end
                        if (this.enableTime) {
                            this.initializeTimeFromDate(end, false)
                        }
                    }
                } else {
                    this.selectedEnd = null
                }

                // Handle month synchronization for range mode
                if (this.selectedStart && this.selectedEnd) {
                    // Check if the range is entirely within one month
                    const isSingleMonthRange = this.isSameMonth(
                        this.selectedStart,
                        this.selectedEnd
                    )

                    if (isSingleMonthRange) {
                        // Case 1: Left calendar already shows the selection month
                        if (this.isDateInMonth(this.selectedStart, this.leftMonth)) {
                            this.leftMonth = new Date(this.selectedStart)
                            // If right calendar also shows the same month (initial load scenario),
                            // set it to the next month. Otherwise, preserve user's navigation.
                            if (
                                this.isDateInMonth(
                                    this.selectedStart,
                                    this.rightMonth
                                )
                            ) {
                                // Both calendars show the same month - set right to next month
                                this.rightMonth = new Date(this.selectedStart)
                                this.rightMonth.setMonth(
                                    this.rightMonth.getMonth() + 1
                                )
                            }
                            // Otherwise, don't change rightMonth - user has navigated it elsewhere
                        }
                        // Case 2: Right calendar already shows the selection month
                        // Skip changing the left calendar
                        else if (
                            this.isDateInMonth(this.selectedStart, this.rightMonth)
                        ) {
                            // Don't change leftMonth - user is already looking at the month on the right
                            this.rightMonth = new Date(this.selectedStart)
                        }
                        // Case 3: Neither calendar shows the selection month
                        // Only update the left calendar
                        else {
                            this.leftMonth = new Date(this.selectedStart)
                            // Keep rightMonth as-is
                        }
                    } else {
                        // Range spans multiple months - update both calendars normally
                        this.leftMonth = new Date(this.selectedStart)
                        this.rightMonth = new Date(this.selectedEnd)
                    }
                } else if (this.selectedStart) {
                    // Only start date is set - update left month, set right to +1 month
                    this.leftMonth = new Date(this.selectedStart)
                    this.rightMonth = new Date(this.leftMonth)
                    this.rightMonth.setMonth(this.rightMonth.getMonth() + 1)
                }
            } else {
                // Single date mode - always update left month
                if (this.selectedStart) {
                    this.leftMonth = new Date(this.selectedStart)
                }
                this.selectedEnd = null
            }
        }
    }

    private initializePresets() {
        if (this.presets.length === 0) {
            this.presets = [
                {
                    label: 'Today',
                    getValue: () => {
                        const today = new Date()
                        return {
                            startDate: today,
                            endDate: this.range ? today : null,
                        }
                    },
                },
                {
                    label: 'Yesterday',
                    getValue: () => {
                        const yesterday = new Date()
                        yesterday.setDate(yesterday.getDate() - 1)
                        return {
                            startDate: yesterday,
                            endDate: this.range ? yesterday : null,
                        }
                    },
                },
                {
                    label: 'Last 7 days',
                    getValue: () => {
                        const end = new Date()
                        const start = new Date()
                        start.setDate(start.getDate() - 6)
                        return { startDate: start, endDate: end }
                    },
                },
                {
                    label: 'Last 30 days',
                    getValue: () => {
                        const end = new Date()
                        const start = new Date()
                        start.setDate(start.getDate() - 29)
                        return { startDate: start, endDate: end }
                    },
                },
                {
                    label: 'Last 6 months',
                    getValue: () => {
                        const end = new Date()
                        const start = new Date()
                        start.setMonth(start.getMonth() - 6)
                        return { startDate: start, endDate: end }
                    },
                },
                {
                    label: 'Last year',
                    getValue: () => {
                        const end = new Date()
                        const start = new Date()
                        start.setFullYear(start.getFullYear() - 1)
                        return { startDate: start, endDate: end }
                    },
                },
                {
                    label: 'All time',
                    getValue: () => {
                        const { min, max } = this.getBounds()
                        return {
                            startDate: min || null,
                            endDate: max || null,
                        }
                    },
                },
            ]
        }
    }

    firstUpdated() {
        // Parse dates from URL or props
        const params = new URLSearchParams(window.location.search)
        const timeStartParam = params.get('time_start') || this.startDate
        const timeEndParam = params.get('time_end') || this.endDate

        if (timeStartParam) {
            this.selectedStart = this.parseLocalDate(timeStartParam)
            this.leftMonth = new Date(this.selectedStart)
            if (this.enableTime) {
                this.initializeTimeFromDate(this.selectedStart, true)
            }
        }

        if (this.range && timeEndParam) {
            this.selectedEnd = this.parseLocalDate(timeEndParam)
            if (this.enableTime) {
                this.initializeTimeFromDate(this.selectedEnd, false)
            }

            // Apply the same month synchronization logic as handleStartEndDateChange
            if (this.selectedStart && this.selectedEnd) {
                const isSingleMonthRange = this.isSameMonth(
                    this.selectedStart,
                    this.selectedEnd
                )

                if (isSingleMonthRange) {
                    // For single-month ranges, set right month to next month
                    this.rightMonth = new Date(this.selectedStart)
                    this.rightMonth.setMonth(this.rightMonth.getMonth() + 1)
                } else {
                    // For multi-month ranges, set right month to end date month
                    this.rightMonth = new Date(this.selectedEnd)
                }
            } else if (this.selectedEnd) {
                // Only end date is set (unusual case)
                this.rightMonth = new Date(this.selectedEnd)
            }
        }

        // Set right month to be one month ahead of left month only if end date wasn't provided
        if (this.range && !timeEndParam) {
            this.rightMonth = new Date(this.leftMonth)
            this.rightMonth.setMonth(this.rightMonth.getMonth() + 1)
        }

        // If inline mode, always show the calendar
        if (this.inline) {
            this.isOpen = true
        }
    }

    disconnectedCallback() {
        super.disconnectedCallback()
        // Dropdown handles its own cleanup
    }

    private handleDropdownShow() {
        this.isOpen = true
    }

    private handleDropdownHide() {
        this.isOpen = false
    }

    private formatDisplayDate(date: Date | null, isStart: boolean = true): string {
        if (!date) return ''

        // Get the format to use
        const format =
            this.displayFormat ||
            (this.enableTime ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD')

        // When time is enabled, use UTC date components and time picker values
        if (this.enableTime) {
            const year = date.getUTCFullYear()
            const month = String(date.getUTCMonth() + 1).padStart(2, '0')
            const day = String(date.getUTCDate()).padStart(2, '0')
            // Use time picker state values instead of date object's time
            const hours = String(isStart ? this.startHour : this.endHour).padStart(
                2,
                '0'
            )
            const minutes = String(
                isStart ? this.startMinute : this.endMinute
            ).padStart(2, '0')
            const seconds = String(
                isStart ? this.startSecond : this.endSecond
            ).padStart(2, '0')

            return format
                .replace('YYYY', year.toString())
                .replace('MM', month)
                .replace('DD', day)
                .replace('HH', hours)
                .replace('mm', minutes)
                .replace('ss', seconds)
        }

        // When time is not enabled, use local date components
        const year = date.getFullYear()
        const month = String(date.getMonth() + 1).padStart(2, '0')
        const day = String(date.getDate()).padStart(2, '0')

        return format
            .replace('YYYY', year.toString())
            .replace('MM', month)
            .replace('DD', day)
    }

    private getDisplayValue(): string {
        if (this.range) {
            if (this.selectedStart && this.selectedEnd) {
                return `${this.formatDisplayDate(this.selectedStart, true)} – ${this.formatDisplayDate(this.selectedEnd, false)}`
            } else if (this.selectedStart) {
                return this.formatDisplayDate(this.selectedStart, true)
            }
            return ''
        } else {
            return this.selectedStart
                ? this.formatDisplayDate(this.selectedStart, true)
                : ''
        }
    }

    private getStartDateDisplayValue(): string {
        return this.selectedStart
            ? this.formatDisplayDate(this.selectedStart, true)
            : ''
    }

    private getEndDateDisplayValue(): string {
        return this.selectedEnd ? this.formatDisplayDate(this.selectedEnd, false) : ''
    }

    private parseAndFormatDate(dateStr: string): string | null {
        const trimmed = dateStr.trim()
        if (!trimmed) return null

        // Check if it's already in YYYY-MM-DD format - use parseLocalDate to avoid timezone issues
        const dateOnlyPattern = /^\d{4}-\d{2}-\d{2}$/
        // Match YYYY-MM-DD HH:mm or YYYY-MM-DD HH:mm:ss (with space or 'T' separator)
        const dateTimePattern = /^\d{4}-\d{2}-\d{2}[T\s]\d{1,2}:\d{2}(:\d{2})?$/
        let date: Date

        if (dateOnlyPattern.test(trimmed)) {
            // Use parseLocalDate for YYYY-MM-DD to avoid timezone issues
            date = this.parseLocalDate(trimmed)
        } else if (this.enableTime && dateTimePattern.test(trimmed)) {
            // For date-time format when time is enabled, parse as UTC to match min/max dates from API
            const [datePart, timePart] = trimmed.split(/[T\s]+/)
            const [year, month, day] = datePart.split('-').map(Number)
            const timeComponents = timePart.split(':').map(Number)
            const hours = timeComponents[0] || 0
            const minutes = timeComponents[1] || 0
            const seconds = timeComponents[2] || 0
            date = new Date(Date.UTC(year, month - 1, day, hours, minutes, seconds))
        } else {
            // For other formats, try new Date() and validate
            date = new Date(trimmed)
            if (!isValid(date)) {
                return null
            }
            // Note: When enableTime is true and we parse via new Date(),
            // the time components will be preserved in the Date object
        }

        if (!isValid(date)) {
            return null
        }

        // Format based on whether time is enabled
        if (this.enableTime) {
            // When time is enabled, check if input was date-only or included time
            if (dateOnlyPattern.test(trimmed)) {
                // User entered date-only (YYYY-MM-DD) - return as-is without adding time
                // The blur handlers will add time from the time picker
                return trimmed
            } else {
                // User entered datetime - format as UTC
                const utcYear = date.getUTCFullYear()
                const utcMonth = date.getUTCMonth() + 1
                const utcDay = date.getUTCDate()
                const utcHours = date.getUTCHours()
                const utcMinutes = date.getUTCMinutes()
                const utcSeconds = date.getUTCSeconds()
                return `${utcYear}-${String(utcMonth).padStart(2, '0')}-${String(utcDay).padStart(2, '0')}T${String(utcHours).padStart(2, '0')}:${String(utcMinutes).padStart(2, '0')}:${String(utcSeconds).padStart(2, '0')}`
            }
        } else {
            // Format to YYYY-MM-DD using the date's local components to avoid timezone issues
            const year = date.getFullYear()
            const month = date.getMonth() + 1
            const day = date.getDate()
            return `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`
        }
    }

    private clearInputValidation() {
        const inputs = this.renderRoot.querySelectorAll<TerraInput>('terra-input')
        inputs.forEach(input => {
            input.setCustomValidity('')
        })
    }

    /**
     * Format a date string for display in error messages
     * When time is disabled, only show the date portion (YYYY-MM-DD)
     */
    private formatDateForError(dateString: string): string {
        if (!this.enableTime) {
            // Extract just the date portion (YYYY-MM-DD) from ISO string
            return dateString.split('T')[0]
        }
        return dateString
    }

    /**
     * Set validation error on input and emit invalid event
     */
    private setInputValidationError(input: TerraInput, message: string) {
        input.setCustomValidity(message)
        // Force validation message to display immediately by directly updating the internal state
        // The terra-input's blur handler already ran, so we need to manually trigger the message update
        requestAnimationFrame(() => {
            // Access the internal validation message property to force display
            ;(input as any).validationErrorMessage = message
            input.requestUpdate()
        })
        this.emit('terra-date-selection-invalid', {
            detail: { message },
        })
    }

    private handleInputBlur(event: Event) {
        const input = event.target as TerraInput
        const value = input.value || ''

        if (!value.trim()) {
            this.selectedStart = null
            this.selectedEnd = null
            input.setCustomValidity('')
            this.emitChange()
            return
        }

        if (this.range) {
            // Split by ' - ' (with spaces)
            const parts = value.split(' - ')
            if (parts.length !== 2) {
                const message =
                    'Date range must be in format: YYYY-MM-DD - YYYY-MM-DD'
                this.setInputValidationError(input, message)
                return
            }

            const startFormatted = this.parseAndFormatDate(parts[0])
            const endFormatted = this.parseAndFormatDate(parts[1])

            if (!startFormatted) {
                const message = 'Invalid start date format'
                this.setInputValidationError(input, message)
                return
            }
            if (!endFormatted) {
                const message = 'Invalid end date format'
                this.setInputValidationError(input, message)
                return
            }

            // When time is enabled, parse as full UTC date; otherwise just date portion
            let start: Date
            let end: Date

            if (this.enableTime && startFormatted.includes('T')) {
                // Full datetime entered for start - parse it and extract time
                start = new Date(startFormatted)
                this.initializeTimeFromDate(start, true)
            } else if (this.enableTime) {
                // Date-only entered for start when time is enabled - parse date as UTC and apply current time picker values
                const [year, month, day] = startFormatted.split('-').map(Number)
                start = new Date(
                    Date.UTC(
                        year,
                        month - 1,
                        day,
                        this.startHour,
                        this.startMinute,
                        this.startSecond
                    )
                )
            } else {
                start = this.parseLocalDate(startFormatted)
            }

            if (this.enableTime && endFormatted.includes('T')) {
                // Full datetime entered for end - parse it and extract time
                end = new Date(endFormatted)
                this.initializeTimeFromDate(end, false)
            } else if (this.enableTime) {
                // Date-only entered for end when time is enabled - parse date as UTC and apply current time picker values
                const [year, month, day] = endFormatted.split('-').map(Number)
                end = new Date(
                    Date.UTC(
                        year,
                        month - 1,
                        day,
                        this.endHour,
                        this.endMinute,
                        this.endSecond
                    )
                )
            } else {
                end = this.parseLocalDate(endFormatted)
            }

            // Auto-swap if dates are in wrong order
            let finalStart = start
            let finalEnd = end
            if (start > end) {
                finalStart = end
                finalEnd = start
            }

            // Validate against min/max dates
            if (this.minDate) {
                const min = this.parseLocalDate(this.minDate)
                if (finalStart < min) {
                    const message = `Start date must be on or after ${this.formatDateForError(this.minDate)}`
                    this.setInputValidationError(input, message)
                    return
                }
            }
            if (this.maxDate) {
                const max = this.parseLocalDate(this.maxDate)
                if (finalEnd > max) {
                    const message = `End date must be on or before ${this.formatDateForError(this.maxDate)}`
                    this.setInputValidationError(input, message)
                    return
                }
            }

            this.selectedStart = finalStart
            this.selectedEnd = finalEnd
            this.updateMonthViews()
            input.value = `${startFormatted} - ${endFormatted}`
            input.setCustomValidity('')
            this.emitChange()
        } else {
            const formatted = this.parseAndFormatDate(value)
            if (!formatted) {
                const message = 'Invalid date format'
                this.setInputValidationError(input, message)
                return
            }

            // When time is enabled, parse as full UTC date; otherwise just date portion
            let date: Date
            if (this.enableTime && formatted.includes('T')) {
                // Full datetime entered - parse it and extract time
                date = new Date(formatted)
                this.initializeTimeFromDate(date, true)
            } else if (this.enableTime) {
                // Date-only entered when time is enabled - parse date as UTC and apply current time picker values
                const [year, month, day] = formatted.split('-').map(Number)
                date = new Date(
                    Date.UTC(
                        year,
                        month - 1,
                        day,
                        this.startHour,
                        this.startMinute,
                        this.startSecond
                    )
                )
            } else {
                // Time not enabled - just parse the date
                date = this.parseLocalDate(formatted)
            }

            // Validate against min/max dates
            if (this.minDate) {
                const min = this.parseLocalDate(this.minDate)
                if (date < min) {
                    const message = `Date must be on or after ${this.formatDateForError(this.minDate)}`
                    this.setInputValidationError(input, message)
                    return
                }
            }
            if (this.maxDate) {
                const max = this.parseLocalDate(this.maxDate)
                if (date > max) {
                    const message = `Date must be on or before ${this.formatDateForError(this.maxDate)}`
                    this.setInputValidationError(input, message)
                    return
                }
            }

            this.selectedStart = date
            this.selectedEnd = null
            this.updateMonthViews()
            input.value = formatted
            input.setCustomValidity('')
            this.emitChange()
        }
    }

    private handleStartInputBlur(event: Event) {
        const input = event.target as TerraInput
        const value = input.value || ''

        if (!value.trim()) {
            this.selectedStart = null
            input.setCustomValidity('')
            this.emitChange()
            return
        }

        const formatted = this.parseAndFormatDate(value)
        if (!formatted) {
            const message = 'Invalid date format'
            this.setInputValidationError(input, message)
            return
        }

        // When time is enabled, parse as full UTC date; otherwise just date portion
        let date: Date
        if (this.enableTime && formatted.includes('T')) {
            // Full datetime entered - parse it and extract time
            date = new Date(formatted)
            this.initializeTimeFromDate(date, true)
        } else if (this.enableTime) {
            // Date-only entered when time is enabled - parse date as UTC and apply current time picker values
            const [year, month, day] = formatted.split('-').map(Number)
            date = new Date(
                Date.UTC(
                    year,
                    month - 1,
                    day,
                    this.startHour,
                    this.startMinute,
                    this.startSecond
                )
            )
        } else {
            // Time not enabled - just parse the date
            date = this.parseLocalDate(formatted)
        }

        // Validate against min/max
        if (this.minDate) {
            const min = this.parseLocalDate(this.minDate)
            if (date < min) {
                const message = `Date must be on or after ${this.formatDateForError(this.minDate)}`
                this.setInputValidationError(input, message)
                return
            }
        }
        if (this.maxDate) {
            const max = this.parseLocalDate(this.maxDate)
            if (date > max) {
                const message = `Date must be on or before ${this.formatDateForError(this.maxDate)}`
                this.setInputValidationError(input, message)
                return
            }
        }

        // Validate start is before end if end exists
        if (this.selectedEnd && date > this.selectedEnd) {
            const message = 'Start date must be before end date'
            this.setInputValidationError(input, message)
            return
        }

        this.selectedStart = date
        this.leftMonth = new Date(date)
        input.value = formatted
        input.setCustomValidity('')
        this.emitChange()
    }

    private handleEndInputBlur(event: Event) {
        const input = event.target as TerraInput
        const value = input.value || ''

        if (!value.trim()) {
            this.selectedEnd = null
            input.setCustomValidity('')
            this.emitChange()
            return
        }

        const formatted = this.parseAndFormatDate(value)
        if (!formatted) {
            const message = 'Invalid date format'
            this.setInputValidationError(input, message)
            return
        }

        // When time is enabled, parse as full UTC date; otherwise just date portion
        let date: Date
        if (this.enableTime && formatted.includes('T')) {
            // Full datetime entered - parse it and extract time
            date = new Date(formatted)
            this.initializeTimeFromDate(date, false)
        } else if (this.enableTime) {
            // Date-only entered when time is enabled - parse date as UTC and apply current time picker values
            const [year, month, day] = formatted.split('-').map(Number)
            date = new Date(
                Date.UTC(
                    year,
                    month - 1,
                    day,
                    this.endHour,
                    this.endMinute,
                    this.endSecond
                )
            )
        } else {
            // Time not enabled - just parse the date
            date = this.parseLocalDate(formatted)
        }

        // Validate against min/max
        if (this.minDate) {
            const min = this.parseLocalDate(this.minDate)
            if (date < min) {
                const message = `Date must be on or after ${this.formatDateForError(this.minDate)}`
                this.setInputValidationError(input, message)
                return
            }
        }
        if (this.maxDate) {
            const max = this.parseLocalDate(this.maxDate)
            if (date > max) {
                const message = `Date must be on or before ${this.formatDateForError(this.maxDate)}`
                this.setInputValidationError(input, message)
                return
            }
        }

        // Validate end is after start if start exists
        if (this.selectedStart) {
            if (this.enableTime && this.isSameDay(date, this.selectedStart)) {
                // When time is enabled and dates are the same, validate time instead of full datetime
                const startTimeSeconds =
                    this.startHour * 3600 + this.startMinute * 60 + this.startSecond
                const endTimeSeconds =
                    this.endHour * 3600 + this.endMinute * 60 + this.endSecond
                if (endTimeSeconds < startTimeSeconds) {
                    const message =
                        'End time must be after start time when dates are the same'
                    this.setInputValidationError(input, message)
                    return
                }
            } else if (date < this.selectedStart) {
                // Different dates or time not enabled - compare full datetime
                const message = 'End date must be after start date'
                this.setInputValidationError(input, message)
                return
            }
        }

        this.selectedEnd = date
        if (
            this.selectedStart &&
            this.isSameMonth(this.selectedStart, this.selectedEnd)
        ) {
            this.rightMonth = new Date(this.selectedStart)
            this.rightMonth.setMonth(this.rightMonth.getMonth() + 1)
        } else {
            this.rightMonth = new Date(date)
        }
        input.setCustomValidity('')
        this.emitChange()
    }

    private updateMonthViews() {
        if (this.selectedStart) {
            this.leftMonth = new Date(this.selectedStart)
            if (this.range && this.selectedEnd) {
                if (this.isSameMonth(this.selectedStart, this.selectedEnd)) {
                    this.rightMonth = new Date(this.selectedStart)
                    this.rightMonth.setMonth(this.rightMonth.getMonth() + 1)
                } else {
                    this.rightMonth = new Date(this.selectedEnd)
                }
            }
        }
    }

    private handleKeydown(event: KeyboardEvent) {
        // Prevent space from opening dropdown when typing
        if (event.key === ' ') {
            event.stopPropagation()
            return
        }
        if (event.key === 'Enter') {
            event.preventDefault()
            this.handleInputBlur(event)
        }
    }

    private previousMonth(isLeft: boolean) {
        if (isLeft) {
            const newMonth = new Date(this.leftMonth)
            newMonth.setMonth(newMonth.getMonth() - 1)
            this.leftMonth = newMonth
        } else {
            const newMonth = new Date(this.rightMonth)
            newMonth.setMonth(newMonth.getMonth() - 1)
            this.rightMonth = newMonth
        }
    }

    private nextMonth(isLeft: boolean) {
        if (isLeft) {
            const newMonth = new Date(this.leftMonth)
            newMonth.setMonth(newMonth.getMonth() + 1)
            this.leftMonth = newMonth
        } else {
            const newMonth = new Date(this.rightMonth)
            newMonth.setMonth(newMonth.getMonth() + 1)
            this.rightMonth = newMonth
        }
    }

    private toggleMonthDropdown(isLeft: boolean, event: Event) {
        event.stopPropagation()
        if (isLeft) {
            this.showLeftMonthDropdown = !this.showLeftMonthDropdown
            this.showRightMonthDropdown = false
        } else {
            this.showRightMonthDropdown = !this.showRightMonthDropdown
            this.showLeftMonthDropdown = false
        }
    }

    private selectMonth(month: number, isLeft: boolean) {
        if (isLeft) {
            const newMonth = new Date(this.leftMonth)
            newMonth.setDate(1) // Set to first day to avoid month overflow
            newMonth.setMonth(month)
            this.leftMonth = newMonth
            this.showLeftMonthDropdown = false
        } else {
            const newMonth = new Date(this.rightMonth)
            newMonth.setDate(1) // Set to first day to avoid month overflow
            newMonth.setMonth(month)
            this.rightMonth = newMonth
            this.showRightMonthDropdown = false
        }
    }

    private changeYear(delta: number, isLeft: boolean) {
        if (isLeft) {
            const newMonth = new Date(this.leftMonth)
            newMonth.setFullYear(newMonth.getFullYear() + delta)
            this.leftMonth = newMonth
        } else {
            const newMonth = new Date(this.rightMonth)
            newMonth.setFullYear(newMonth.getFullYear() + delta)
            this.rightMonth = newMonth
        }
    }

    private handleYearInput(event: Event, isLeft: boolean) {
        const input = event.target as HTMLInputElement
        const year = parseInt(input.value, 10)

        if (!isNaN(year) && year >= 1900 && year <= 2100) {
            if (isLeft) {
                const newMonth = new Date(this.leftMonth)
                newMonth.setFullYear(year)
                this.leftMonth = newMonth
            } else {
                const newMonth = new Date(this.rightMonth)
                newMonth.setFullYear(year)
                this.rightMonth = newMonth
            }
        }
    }

    private getDaysInMonth(date: Date): Date[] {
        const year = date.getFullYear()
        const month = date.getMonth()

        // When time is enabled, create dates in UTC to match how selectedStart/selectedEnd are stored
        // When time is disabled, use local dates
        const createDate = (y: number, m: number, d: number) => {
            if (this.enableTime) {
                return new Date(Date.UTC(y, m, d, 0, 0, 0))
            }
            return new Date(y, m, d)
        }

        const firstDay = createDate(year, month, 1)
        const lastDay = new Date(year, month + 1, 0)

        const days: Date[] = []

        // Add previous month's trailing days
        const firstDayOfWeek = this.enableTime
            ? firstDay.getUTCDay()
            : firstDay.getDay()
        for (let i = firstDayOfWeek - 1; i >= 0; i--) {
            const day = createDate(year, month, -i)
            days.push(day)
        }

        // Add current month's days
        for (let i = 1; i <= lastDay.getDate(); i++) {
            days.push(createDate(year, month, i))
        }

        // Add next month's leading days to complete the week
        const remainingDays = 7 - (days.length % 7)
        if (remainingDays < 7) {
            for (let i = 1; i <= remainingDays; i++) {
                days.push(createDate(year, month + 1, i))
            }
        }

        return days
    }

    private isSameDay(date1: Date | null, date2: Date | null): boolean {
        if (!date1 || !date2) return false

        // When time is enabled, compare UTC date components
        // When time is disabled, compare local date components
        if (this.enableTime) {
            return (
                date1.getUTCFullYear() === date2.getUTCFullYear() &&
                date1.getUTCMonth() === date2.getUTCMonth() &&
                date1.getUTCDate() === date2.getUTCDate()
            )
        }

        return (
            date1.getFullYear() === date2.getFullYear() &&
            date1.getMonth() === date2.getMonth() &&
            date1.getDate() === date2.getDate()
        )
    }

    private isInRange(date: Date): boolean {
        if (!this.selectedStart || !this.selectedEnd) return false
        const time = date.getTime()
        return (
            time >= this.selectedStart.getTime() && time <= this.selectedEnd.getTime()
        )
    }

    private isInHoverRange(date: Date): boolean {
        if (!this.range || !this.selectedStart || !this.hoverDate || this.selectedEnd)
            return false
        const time = date.getTime()
        const start = Math.min(this.selectedStart.getTime(), this.hoverDate.getTime())
        const end = Math.max(this.selectedStart.getTime(), this.hoverDate.getTime())
        return time >= start && time <= end
    }

    private isDisabled(date: Date): boolean {
        if (this.minDate) {
            const min = this.parseLocalDate(this.minDate)
            // Use UTC for comparison to avoid timezone issues with API dates
            const minMidnight = new Date(
                Date.UTC(min.getUTCFullYear(), min.getUTCMonth(), min.getUTCDate())
            )
            const dateMidnight = new Date(
                Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate())
            )
            if (dateMidnight < minMidnight) return true
        }
        if (this.maxDate) {
            const max = this.parseLocalDate(this.maxDate)
            // Use UTC for comparison to avoid timezone issues with API dates
            const maxMidnight = new Date(
                Date.UTC(max.getUTCFullYear(), max.getUTCMonth(), max.getUTCDate())
            )
            const dateMidnight = new Date(
                Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate())
            )
            if (dateMidnight > maxMidnight) return true
        }
        return false
    }

    selectDate(date: Date) {
        if (this.isDisabled(date)) {
            this.emit('terra-date-selection-invalid', {
                detail: {
                    message: `You are not allowed to select dates outside ${this.minDate} to ${this.maxDate}.`,
                },
            })
            return
        }

        this.clearInputValidation()

        if (this.range) {
            if (!this.selectedStart || this.selectedEnd) {
                // Start new selection
                this.selectedStart = date
                this.selectedEnd = null
                this.isSelectingRange = true
            } else {
                // Complete the range
                if (date < this.selectedStart) {
                    this.selectedEnd = this.selectedStart
                    this.selectedStart = date
                } else {
                    this.selectedEnd = date
                }

                this.isSelectingRange = false

                // When time is enabled and both dates are the same day,
                // emit validation event if end time < start time
                if (
                    this.enableTime &&
                    this.selectedStart &&
                    this.selectedEnd &&
                    this.isSameDay(this.selectedStart, this.selectedEnd)
                ) {
                    const startTimeSeconds =
                        this.startHour * 3600 +
                        this.startMinute * 60 +
                        this.startSecond
                    const endTimeSeconds =
                        this.endHour * 3600 + this.endMinute * 60 + this.endSecond
                    if (endTimeSeconds < startTimeSeconds) {
                        this.emit('terra-date-selection-invalid', {
                            detail: {
                                message:
                                    'End time is before start time. Please adjust the time values.',
                            },
                        })
                    }
                }

                this.emitChange()
                if (!this.inline) {
                    this.isOpen = false
                }
            }
        } else {
            this.selectedStart = date
            this.selectedEnd = null
            this.emitChange()
            if (!this.inline) {
                this.isOpen = false
            }
        }
    }

    private handleDateHover(date: Date) {
        if (this.range && this.selectedStart && !this.selectedEnd) {
            this.hoverDate = date
        }
    }

    private selectPreset(preset: PresetRange) {
        const { startDate, endDate } = preset.getValue()

        if (!this.isPresetWithinBounds({ startDate, endDate })) {
            this.emit('terra-date-selection-invalid', {
                detail: {
                    message: `The preset "${preset.label}" is not available within the allowed date range ${this.minDate} to ${this.maxDate}.`,
                },
            })
            return
        }

        // Clear any validation errors when selecting a preset
        this.clearInputValidation()

        const { min, max } = this.getBounds()

        if (this.range) {
            let s = startDate
            let e = endDate
            if (s && min && s < min) s = new Date(min)
            if (s && max && s > max) s = new Date(max)
            if (e && min && e < min) e = new Date(min)
            if (e && max && e > max) e = new Date(max)
            if (s && e && e < s) {
                const tmp = s
                s = e
                e = tmp
            }
            this.selectedStart = s
            this.selectedEnd = e
        } else {
            let s = startDate
            if (s && min && s < min) s = new Date(min)
            if (s && max && s > max) s = new Date(max)
            this.selectedStart = s
            this.selectedEnd = null
        }

        if (this.selectedStart) {
            this.leftMonth = new Date(this.selectedStart)
            if (this.range && this.selectedEnd) {
                this.rightMonth = new Date(this.selectedEnd)
            }
        }

        this.emitChange()
        if (!this.range && !this.inline) {
            this.isOpen = false
        }
    }

    private emitChange() {
        let startDateTime = ''
        let endDateTime = ''

        if (this.selectedStart) {
            if (this.enableTime) {
                const startDate = new Date(this.selectedStart)
                startDate.setUTCHours(
                    this.startHour,
                    this.startMinute,
                    this.startSecond,
                    0
                )
                startDateTime = startDate.toISOString()
            } else {
                // Format using local date components to avoid timezone conversion issues
                const year = this.selectedStart.getFullYear()
                const month = String(this.selectedStart.getMonth() + 1).padStart(
                    2,
                    '0'
                )
                const day = String(this.selectedStart.getDate()).padStart(2, '0')
                startDateTime = `${year}-${month}-${day}`
            }
        }

        if (this.selectedEnd) {
            if (this.enableTime) {
                const endDate = new Date(this.selectedEnd)
                endDate.setUTCHours(this.endHour, this.endMinute, this.endSecond, 0)
                endDateTime = endDate.toISOString()
            } else {
                // Format using local date components to avoid timezone conversion issues
                const year = this.selectedEnd.getFullYear()
                const month = String(this.selectedEnd.getMonth() + 1).padStart(2, '0')
                const day = String(this.selectedEnd.getDate()).padStart(2, '0')
                endDateTime = `${year}-${month}-${day}`
            }
        }

        this.emit('terra-date-range-change', {
            detail: {
                startDate: startDateTime,
                endDate: endDateTime,
            },
        })
    }

    private initializeTimeFromDate(date: Date, isStart: boolean) {
        const hours = date.getUTCHours()
        const minutes = date.getUTCMinutes()
        const seconds = date.getUTCSeconds()

        if (isStart) {
            this.startHour = hours
            this.startMinute = minutes
            this.startSecond = seconds
        } else {
            this.endHour = hours
            this.endMinute = minutes
            this.endSecond = seconds
        }
    }

    private changeTime(
        type: 'hour' | 'minute' | 'second',
        delta: number,
        isStart: boolean
    ) {
        if (type === 'hour') {
            if (isStart) {
                let newHour = this.startHour + delta
                if (newHour > 23) newHour = 0
                if (newHour < 0) newHour = 23
                this.startHour = newHour
            } else {
                let newHour = this.endHour + delta
                if (newHour > 23) newHour = 0
                if (newHour < 0) newHour = 23
                this.endHour = newHour
            }
        } else if (type === 'minute') {
            if (isStart) {
                let newMinute = this.startMinute + delta
                if (newMinute >= 60) newMinute = 0
                if (newMinute < 0) newMinute = 59
                this.startMinute = newMinute
            } else {
                let newMinute = this.endMinute + delta
                if (newMinute >= 60) newMinute = 0
                if (newMinute < 0) newMinute = 59
                this.endMinute = newMinute
            }
        } else {
            if (isStart) {
                let newSecond = this.startSecond + delta
                if (newSecond >= 60) newSecond = 0
                if (newSecond < 0) newSecond = 59
                this.startSecond = newSecond
            } else {
                let newSecond = this.endSecond + delta
                if (newSecond >= 60) newSecond = 0
                if (newSecond < 0) newSecond = 59
                this.endSecond = newSecond
            }
        }
        this.emitChange()
        this.requestUpdate()
    }

    private handleTimeInput(
        event: Event,
        type: 'hour' | 'minute' | 'second',
        isStart: boolean
    ) {
        const input = event.target as HTMLInputElement
        let value = parseInt(input.value, 10)

        if (type === 'hour') {
            if (isNaN(value) || value < 0 || value > 23) {
                input.value = isStart
                    ? this.startHour.toString().padStart(2, '0')
                    : this.endHour.toString().padStart(2, '0')
                return
            }
            if (isStart) this.startHour = value
            else this.endHour = value
        } else if (type === 'minute') {
            if (isNaN(value) || value < 0 || value >= 60) {
                input.value = isStart
                    ? this.startMinute.toString().padStart(2, '0')
                    : this.endMinute.toString().padStart(2, '0')
                return
            }
            if (isStart) this.startMinute = value
            else this.endMinute = value
        } else {
            if (isNaN(value) || value < 0 || value >= 60) {
                input.value = isStart
                    ? this.startSecond.toString().padStart(2, '0')
                    : this.endSecond.toString().padStart(2, '0')
                return
            }
            if (isStart) this.startSecond = value
            else this.endSecond = value
        }
        this.emitChange()
        this.requestUpdate()
    }

    private renderCalendar(month: Date, isLeft: boolean = true) {
        const days = this.getDaysInMonth(month)
        const currentMonth = month.getMonth()
        const showDropdown = isLeft
            ? this.showLeftMonthDropdown
            : this.showRightMonthDropdown

        return html`
            <div class="calendar">
                <div class="calendar__header">
                    <button
                        type="button"
                        class="calendar__nav"
                        @click=${() => this.previousMonth(isLeft)}
                    >
                        <svg width="16" height="16" viewBox="0 0 16 16" fill="none">
                            <path
                                d="M10 12L6 8L10 4"
                                stroke="currentColor"
                                stroke-width="2"
                                stroke-linecap="round"
                                stroke-linejoin="round"
                            />
                        </svg>
                    </button>

                    <div class="calendar__month-year">
                        <div class="calendar__month-dropdown-wrapper">
                            <button
                                type="button"
                                class="calendar__month-button"
                                @click=${(e: Event) =>
                                    this.toggleMonthDropdown(isLeft, e)}
                            >
                                ${this.MONTHS[month.getMonth()]}
                                <svg
                                    width="12"
                                    height="12"
                                    viewBox="0 0 12 12"
                                    fill="none"
                                    class="calendar__month-icon"
                                >
                                    <path
                                        d="M3 5L6 8L9 5"
                                        stroke="currentColor"
                                        stroke-width="1.5"
                                        stroke-linecap="round"
                                        stroke-linejoin="round"
                                    />
                                </svg>
                            </button>

                            ${showDropdown
                                ? html`
                                      <div class="calendar__month-dropdown">
                                          ${this.MONTHS.map(
                                              (monthName, index) => html`
                                                  <button
                                                      type="button"
                                                      class="calendar__month-option ${index ===
                                                      month.getMonth()
                                                          ? 'calendar__month-option--selected'
                                                          : ''}"
                                                      @click=${() =>
                                                          this.selectMonth(
                                                              index,
                                                              isLeft
                                                          )}
                                                  >
                                                      ${index === month.getMonth()
                                                          ? html`
                                                                <svg
                                                                    width="16"
                                                                    height="16"
                                                                    viewBox="0 0 16 16"
                                                                    fill="none"
                                                                    class="calendar__month-check"
                                                                >
                                                                    <path
                                                                        d="M13 4L6 11L3 8"
                                                                        stroke="currentColor"
                                                                        stroke-width="2"
                                                                        stroke-linecap="round"
                                                                        stroke-linejoin="round"
                                                                    />
                                                                </svg>
                                                            `
                                                          : ''}
                                                      ${monthName}
                                                  </button>
                                              `
                                          )}
                                      </div>
                                  `
                                : ''}
                        </div>

                        <div class="calendar__year-input-wrapper">
                            <input
                                type="number"
                                class="calendar__year-input"
                                .value=${month.getFullYear().toString()}
                                @input=${(e: Event) =>
                                    this.handleYearInput(e, isLeft)}
                                @blur=${(e: Event) => {
                                    const input = e.target as HTMLInputElement
                                    input.value = month.getFullYear().toString()
                                }}
                                min="1900"
                                max="2100"
                            />
                            <div class="calendar__year-spinners">
                                <button
                                    type="button"
                                    class="calendar__year-spinner calendar__year-spinner--up"
                                    @click=${() => this.changeYear(1, isLeft)}
                                >
                                    <svg
                                        width="10"
                                        height="10"
                                        viewBox="0 0 10 10"
                                        fill="none"
                                    >
                                        <path
                                            d="M2 6L5 3L8 6"
                                            stroke="currentColor"
                                            stroke-width="1.5"
                                            stroke-linecap="round"
                                            stroke-linejoin="round"
                                        />
                                    </svg>
                                </button>
                                <button
                                    type="button"
                                    class="calendar__year-spinner calendar__year-spinner--down"
                                    @click=${() => this.changeYear(-1, isLeft)}
                                >
                                    <svg
                                        width="10"
                                        height="10"
                                        viewBox="0 0 10 10"
                                        fill="none"
                                    >
                                        <path
                                            d="M2 4L5 7L8 4"
                                            stroke="currentColor"
                                            stroke-width="1.5"
                                            stroke-linecap="round"
                                            stroke-linejoin="round"
                                        />
                                    </svg>
                                </button>
                            </div>
                        </div>
                    </div>

                    <button
                        type="button"
                        class="calendar__nav"
                        @click=${() => this.nextMonth(isLeft)}
                    >
                        <svg width="16" height="16" viewBox="0 0 16 16" fill="none">
                            <path
                                d="M6 12L10 8L6 4"
                                stroke="currentColor"
                                stroke-width="2"
                                stroke-linecap="round"
                                stroke-linejoin="round"
                            />
                        </svg>
                    </button>
                </div>
                <div class="calendar__weekdays">
                    ${this.DAYS.map(
                        day => html`<div class="calendar__weekday">${day}</div>`
                    )}
                </div>
                <div class="calendar__days">
                    ${days.map(date => {
                        // When time is enabled, use UTC components; otherwise use local
                        const dateMonth = this.enableTime
                            ? date.getUTCMonth()
                            : date.getMonth()
                        const dateDay = this.enableTime
                            ? date.getUTCDate()
                            : date.getDate()

                        const isCurrentMonth = dateMonth === currentMonth
                        const isSelected =
                            this.isSameDay(date, this.selectedStart) ||
                            this.isSameDay(date, this.selectedEnd)
                        const isStart = this.isSameDay(date, this.selectedStart)
                        const isEnd = this.isSameDay(date, this.selectedEnd)
                        const inRange = this.isInRange(date)
                        const inHoverRange = this.isInHoverRange(date)
                        const isDisabled = this.isDisabled(date)

                        return html`
                            <button
                                type="button"
                                class="calendar__day ${!isCurrentMonth
                                    ? 'calendar__day--outside'
                                    : ''} 
                                       ${isSelected ? 'calendar__day--selected' : ''}
                                       ${isStart ? 'calendar__day--start' : ''}
                                       ${isEnd ? 'calendar__day--end' : ''}
                                       ${inRange ? 'calendar__day--in-range' : ''}
                                       ${inHoverRange
                                    ? 'calendar__day--hover-range'
                                    : ''}
                                       ${isDisabled ? 'calendar__day--disabled' : ''}"
                                @click=${() => this.selectDate(date)}
                                @mouseenter=${() => this.handleDateHover(date)}
                                ?disabled=${isDisabled}
                            >
                                ${dateDay}
                            </button>
                        `
                    })}
                </div>
            </div>
        `
    }

    private renderTimePicker() {
        if (!this.enableTime) return ''

        return html`
            <div class="date-picker__time">
                <div class="date-picker__time-section">
                    <div class="date-picker__time-inputs">
                        <div class="date-picker__time-input-group">
                            <input
                                type="number"
                                class="date-picker__time-input"
                                .value=${this.startHour.toString().padStart(2, '0')}
                                @input=${(e: Event) =>
                                    this.handleTimeInput(e, 'hour', true)}
                                @blur=${(e: Event) => {
                                    const input = e.target as HTMLInputElement
                                    input.value = this.startHour
                                        .toString()
                                        .padStart(2, '0')
                                }}
                                min="0"
                                max="23"
                            />
                            <div class="date-picker__time-spinners">
                                <button
                                    type="button"
                                    class="date-picker__time-spinner"
                                    @click=${() => this.changeTime('hour', 1, true)}
                                >
                                    <svg
                                        width="10"
                                        height="10"
                                        viewBox="0 0 10 10"
                                        fill="none"
                                    >
                                        <path
                                            d="M2 6L5 3L8 6"
                                            stroke="currentColor"
                                            stroke-width="1.5"
                                            stroke-linecap="round"
                                            stroke-linejoin="round"
                                        />
                                    </svg>
                                </button>
                                <button
                                    type="button"
                                    class="date-picker__time-spinner"
                                    @click=${() => this.changeTime('hour', -1, true)}
                                >
                                    <svg
                                        width="10"
                                        height="10"
                                        viewBox="0 0 10 10"
                                        fill="none"
                                    >
                                        <path
                                            d="M2 4L5 7L8 4"
                                            stroke="currentColor"
                                            stroke-width="1.5"
                                            stroke-linecap="round"
                                            stroke-linejoin="round"
                                        />
                                    </svg>
                                </button>
                            </div>
                        </div>

                        <span class="date-picker__time-separator">:</span>

                        <div class="date-picker__time-input-group">
                            <input
                                type="number"
                                class="date-picker__time-input"
                                .value=${this.startMinute.toString().padStart(2, '0')}
                                @input=${(e: Event) =>
                                    this.handleTimeInput(e, 'minute', true)}
                                @blur=${(e: Event) => {
                                    const input = e.target as HTMLInputElement
                                    input.value = this.startMinute
                                        .toString()
                                        .padStart(2, '0')
                                }}
                                min="0"
                                max="59"
                            />
                            <div class="date-picker__time-spinners">
                                <button
                                    type="button"
                                    class="date-picker__time-spinner"
                                    @click=${() => this.changeTime('minute', 1, true)}
                                >
                                    <svg
                                        width="10"
                                        height="10"
                                        viewBox="0 0 10 10"
                                        fill="none"
                                    >
                                        <path
                                            d="M2 6L5 3L8 6"
                                            stroke="currentColor"
                                            stroke-width="1.5"
                                            stroke-linecap="round"
                                            stroke-linejoin="round"
                                        />
                                    </svg>
                                </button>
                                <button
                                    type="button"
                                    class="date-picker__time-spinner"
                                    @click=${() =>
                                        this.changeTime('minute', -1, true)}
                                >
                                    <svg
                                        width="10"
                                        height="10"
                                        viewBox="0 0 10 10"
                                        fill="none"
                                    >
                                        <path
                                            d="M2 4L5 7L8 4"
                                            stroke="currentColor"
                                            stroke-width="1.5"
                                            stroke-linecap="round"
                                            stroke-linejoin="round"
                                        />
                                    </svg>
                                </button>
                            </div>
                        </div>

                        <span class="date-picker__time-separator">:</span>

                        <div class="date-picker__time-input-group">
                            <input
                                type="number"
                                class="date-picker__time-input"
                                .value=${this.startSecond.toString().padStart(2, '0')}
                                @input=${(e: Event) =>
                                    this.handleTimeInput(e, 'second', true)}
                                @blur=${(e: Event) => {
                                    const input = e.target as HTMLInputElement
                                    input.value = this.startSecond
                                        .toString()
                                        .padStart(2, '0')
                                }}
                                min="0"
                                max="59"
                            />
                            <div class="date-picker__time-spinners">
                                <button
                                    type="button"
                                    class="date-picker__time-spinner"
                                    @click=${() => this.changeTime('second', 1, true)}
                                >
                                    <svg
                                        width="10"
                                        height="10"
                                        viewBox="0 0 10 10"
                                        fill="none"
                                    >
                                        <path
                                            d="M2 6L5 3L8 6"
                                            stroke="currentColor"
                                            stroke-width="1.5"
                                            stroke-linecap="round"
                                            stroke-linejoin="round"
                                        />
                                    </svg>
                                </button>
                                <button
                                    type="button"
                                    class="date-picker__time-spinner"
                                    @click=${() =>
                                        this.changeTime('second', -1, true)}
                                >
                                    <svg
                                        width="10"
                                        height="10"
                                        viewBox="0 0 10 10"
                                        fill="none"
                                    >
                                        <path
                                            d="M2 4L5 7L8 4"
                                            stroke="currentColor"
                                            stroke-width="1.5"
                                            stroke-linecap="round"
                                            stroke-linejoin="round"
                                        />
                                    </svg>
                                </button>
                            </div>
                        </div>
                    </div>
                </div>

                ${this.range
                    ? html`
                          <span class="date-picker__separator">–</span>

                          <div class="date-picker__time-section">
                              <div class="date-picker__time-inputs">
                                  <div class="date-picker__time-input-group">
                                      <input
                                          type="number"
                                          class="date-picker__time-input"
                                          .value=${this.endHour
                                              .toString()
                                              .padStart(2, '0')}
                                          @input=${(e: Event) =>
                                              this.handleTimeInput(e, 'hour', false)}
                                          @blur=${(e: Event) => {
                                              const input =
                                                  e.target as HTMLInputElement
                                              input.value = this.endHour
                                                  .toString()
                                                  .padStart(2, '0')
                                          }}
                                          min="0"
                                          max="23"
                                      />
                                      <div class="date-picker__time-spinners">
                                          <button
                                              type="button"
                                              class="date-picker__time-spinner"
                                              @click=${() =>
                                                  this.changeTime('hour', 1, false)}
                                          >
                                              <svg
                                                  width="10"
                                                  height="10"
                                                  viewBox="0 0 10 10"
                                                  fill="none"
                                              >
                                                  <path
                                                      d="M2 6L5 3L8 6"
                                                      stroke="currentColor"
                                                      stroke-width="1.5"
                                                      stroke-linecap="round"
                                                      stroke-linejoin="round"
                                                  />
                                              </svg>
                                          </button>
                                          <button
                                              type="button"
                                              class="date-picker__time-spinner"
                                              @click=${() =>
                                                  this.changeTime('hour', -1, false)}
                                          >
                                              <svg
                                                  width="10"
                                                  height="10"
                                                  viewBox="0 0 10 10"
                                                  fill="none"
                                              >
                                                  <path
                                                      d="M2 4L5 7L8 4"
                                                      stroke="currentColor"
                                                      stroke-width="1.5"
                                                      stroke-linecap="round"
                                                      stroke-linejoin="round"
                                                  />
                                              </svg>
                                          </button>
                                      </div>
                                  </div>

                                  <span class="date-picker__time-separator">:</span>

                                  <div class="date-picker__time-input-group">
                                      <input
                                          type="number"
                                          class="date-picker__time-input"
                                          .value=${this.endMinute
                                              .toString()
                                              .padStart(2, '0')}
                                          @input=${(e: Event) =>
                                              this.handleTimeInput(
                                                  e,
                                                  'minute',
                                                  false
                                              )}
                                          @blur=${(e: Event) => {
                                              const input =
                                                  e.target as HTMLInputElement
                                              input.value = this.endMinute
                                                  .toString()
                                                  .padStart(2, '0')
                                          }}
                                          min="0"
                                          max="59"
                                      />
                                      <div class="date-picker__time-spinners">
                                          <button
                                              type="button"
                                              class="date-picker__time-spinner"
                                              @click=${() =>
                                                  this.changeTime('minute', 1, false)}
                                          >
                                              <svg
                                                  width="10"
                                                  height="10"
                                                  viewBox="0 0 10 10"
                                                  fill="none"
                                              >
                                                  <path
                                                      d="M2 6L5 3L8 6"
                                                      stroke="currentColor"
                                                      stroke-width="1.5"
                                                      stroke-linecap="round"
                                                      stroke-linejoin="round"
                                                  />
                                              </svg>
                                          </button>
                                          <button
                                              type="button"
                                              class="date-picker__time-spinner"
                                              @click=${() =>
                                                  this.changeTime(
                                                      'minute',
                                                      -1,
                                                      false
                                                  )}
                                          >
                                              <svg
                                                  width="10"
                                                  height="10"
                                                  viewBox="0 0 10 10"
                                                  fill="none"
                                              >
                                                  <path
                                                      d="M2 4L5 7L8 4"
                                                      stroke="currentColor"
                                                      stroke-width="1.5"
                                                      stroke-linecap="round"
                                                      stroke-linejoin="round"
                                                  />
                                              </svg>
                                          </button>
                                      </div>
                                  </div>

                                  <span class="date-picker__time-separator">:</span>

                                  <div class="date-picker__time-input-group">
                                      <input
                                          type="number"
                                          class="date-picker__time-input"
                                          .value=${this.endSecond
                                              .toString()
                                              .padStart(2, '0')}
                                          @input=${(e: Event) =>
                                              this.handleTimeInput(
                                                  e,
                                                  'second',
                                                  false
                                              )}
                                          @blur=${(e: Event) => {
                                              const input =
                                                  e.target as HTMLInputElement
                                              input.value = this.endSecond
                                                  .toString()
                                                  .padStart(2, '0')
                                          }}
                                          min="0"
                                          max="59"
                                      />
                                      <div class="date-picker__time-spinners">
                                          <button
                                              type="button"
                                              class="date-picker__time-spinner"
                                              @click=${() =>
                                                  this.changeTime('second', 1, false)}
                                          >
                                              <svg
                                                  width="10"
                                                  height="10"
                                                  viewBox="0 0 10 10"
                                                  fill="none"
                                              >
                                                  <path
                                                      d="M2 6L5 3L8 6"
                                                      stroke="currentColor"
                                                      stroke-width="1.5"
                                                      stroke-linecap="round"
                                                      stroke-linejoin="round"
                                                  />
                                              </svg>
                                          </button>
                                          <button
                                              type="button"
                                              class="date-picker__time-spinner"
                                              @click=${() =>
                                                  this.changeTime(
                                                      'second',
                                                      -1,
                                                      false
                                                  )}
                                          >
                                              <svg
                                                  width="10"
                                                  height="10"
                                                  viewBox="0 0 10 10"
                                                  fill="none"
                                              >
                                                  <path
                                                      d="M2 4L5 7L8 4"
                                                      stroke="currentColor"
                                                      stroke-width="1.5"
                                                      stroke-linecap="round"
                                                      stroke-linejoin="round"
                                                  />
                                              </svg>
                                          </button>
                                      </div>
                                  </div>
                              </div>
                          </div>
                      `
                    : ''}
            </div>
        `
    }

    private renderCalendarIcon() {
        return html`
            <svg
                slot="suffix"
                class="date-picker__icon"
                width="20"
                height="20"
                viewBox="0 0 24 24"
                fill="none"
                stroke="currentColor"
                stroke-width="2"
            >
                <rect x="3" y="4" width="18" height="18" rx="2" ry="2"></rect>
                <line x1="16" y1="2" x2="16" y2="6"></line>
                <line x1="8" y1="2" x2="8" y2="6"></line>
                <line x1="3" y1="10" x2="21" y2="10"></line>
            </svg>
        `
    }

    private renderCalendarContent() {
        return html`
            <div class="date-picker__dropdown" part="calendar">
                <div class="date-picker__content">
                    ${this.showPresets && this.filteredPresets.length > 0
                        ? html`
                              <div class="date-picker__sidebar" part="sidebar">
                                  <slot name="sidebar-header"></slot>

                                  <div class="presets">
                                      ${this.filteredPresets.map(
                                          preset => html`
                                              <button
                                                  type="button"
                                                  class="date-picker__preset"
                                                  @click=${() =>
                                                      this.selectPreset(preset)}
                                              >
                                                  ${preset.label}
                                              </button>
                                          `
                                      )}
                                  </div>

                                  <slot name="sidebar-footer">
                                      <terra-button
                                          outline
                                          variant="default"
                                          size="small"
                                          @click=${() => this.clear()}
                                      >
                                          ${this.clearAllLabel}
                                      </terra-button>
                                  </slot>
                              </div>
                          `
                        : ''}

                    <div class="date-picker__calendars">
                        ${this.renderCalendar(this.leftMonth, true)}
                        ${this.range
                            ? this.renderCalendar(this.rightMonth, false)
                            : ''}
                    </div>
                </div>

                ${this.enableTime ? this.renderTimePicker() : ''}
            </div>
        `
    }

    render() {
        const showSplitInputs = this.range && this.splitInputs

        // Inline mode: render directly without dropdown
        if (this.inline) {
            return html`
                <div
                    class="date-picker date-picker--inline ${showSplitInputs
                        ? 'date-picker--split-inputs'
                        : ''}"
                    @click=${(e: Event) => e.stopPropagation()}
                >
                    ${showSplitInputs
                        ? html`
                              <div class="date-picker__inputs">
                                  <terra-input
                                      .label=${this.startLabel ||
                                      (this.label
                                          ? `${this.label} (Start)`
                                          : 'Start Date')}
                                      .hideLabel=${this.hideLabel}
                                      .helpText=${this.startHelpText || this.helpText}
                                      .value=${this.getStartDateDisplayValue()}
                                      @terra-blur=${this.handleStartInputBlur}
                                      @keydown=${this.handleKeydown}
                                      placeholder=${this.startPlaceholder}
                                      name="start-date"
                                  >
                                      ${this.renderCalendarIcon()}
                                  </terra-input>
                                  <terra-input
                                      .label=${this.endLabel ||
                                      (this.label
                                          ? `${this.label} (End)`
                                          : 'End Date')}
                                      .hideLabel=${this.hideLabel}
                                      .helpText=${this.endHelpText || this.helpText}
                                      .value=${this.getEndDateDisplayValue()}
                                      @terra-blur=${this.handleEndInputBlur}
                                      @keydown=${this.handleKeydown}
                                      placeholder=${this.endPlaceholder}
                                      name="end-date"
                                  >
                                      ${this.renderCalendarIcon()}
                                  </terra-input>
                              </div>
                          `
                        : html`
                              <terra-input
                                  .label=${this.label}
                                  .hideLabel=${this.hideLabel}
                                  .helpText=${this.helpText}
                                  .value=${this.getDisplayValue()}
                                  placeholder=${this.placeholder}
                                  @terra-blur=${this.handleInputBlur}
                                  @keydown=${this.handleKeydown}
                                  name="date"
                              >
                                  ${this.renderCalendarIcon()}
                              </terra-input>
                          `}

                    <slot name="additional-text"></slot>

                    <div class="date-picker__dropdown-wrapper">
                        <div
                            class="date-picker__dropdown date-picker__dropdown--inline"
                            part="calendar"
                        >
                            <div class="date-picker__content">
                                ${this.showPresets && this.filteredPresets.length > 0
                                    ? html`
                                          <div
                                              class="date-picker__sidebar"
                                              part="sidebar"
                                          >
                                              <slot name="sidebar-header"></slot>

                                              <div class="presets">
                                                  ${this.filteredPresets.map(
                                                      preset => html`
                                                          <button
                                                              type="button"
                                                              class="date-picker__preset"
                                                              @click=${() =>
                                                                  this.selectPreset(
                                                                      preset
                                                                  )}
                                                          >
                                                              ${preset.label}
                                                          </button>
                                                      `
                                                  )}
                                              </div>

                                              <slot name="sidebar-footer">
                                                  <terra-button
                                                      outline
                                                      variant="default"
                                                      size="small"
                                                      @click=${() => this.clear()}
                                                  >
                                                      ${this.clearAllLabel}
                                                  </terra-button>
                                              </slot>
                                          </div>
                                      `
                                    : ''}

                                <div class="date-picker__calendars">
                                    ${this.renderCalendar(this.leftMonth, true)}
                                    ${this.range
                                        ? this.renderCalendar(this.rightMonth, false)
                                        : ''}
                                </div>
                            </div>

                            ${this.enableTime ? this.renderTimePicker() : ''}
                        </div>
                    </div>
                </div>
            `
        }

        // Non-inline mode: use dropdown
        return html`
            <div
                class="date-picker ${showSplitInputs
                    ? 'date-picker--split-inputs'
                    : ''}"
                @click=${(e: Event) => e.stopPropagation()}
            >
                ${showSplitInputs
                    ? html`
                          <div class="date-picker__inputs">
                              <terra-dropdown
                                  ${ref(this.dropdownRef)}
                                  placement="bottom-start"
                                  distance="4"
                                  @terra-show=${this.handleDropdownShow}
                                  @terra-hide=${this.handleDropdownHide}
                                  hoist
                              >
                                  <terra-input
                                      slot="trigger"
                                      .label=${this.startLabel ||
                                      (this.label
                                          ? `${this.label} (Start)`
                                          : 'Start Date')}
                                      .hideLabel=${this.hideLabel}
                                      .helpText=${this.startHelpText || this.helpText}
                                      .value=${this.getStartDateDisplayValue()}
                                      placeholder=${this.startPlaceholder}
                                      @terra-blur=${this.handleStartInputBlur}
                                      @keydown=${this.handleKeydown}
                                      name="start-date"
                                  >
                                      ${this.renderCalendarIcon()}
                                  </terra-input>
                                  ${this.renderCalendarContent()}
                              </terra-dropdown>
                              <terra-dropdown
                                  placement="bottom-start"
                                  distance="4"
                                  @terra-show=${this.handleDropdownShow}
                                  @terra-hide=${this.handleDropdownHide}
                                  hoist
                              >
                                  <terra-input
                                      slot="trigger"
                                      .label=${this.endLabel ||
                                      (this.label
                                          ? `${this.label} (End)`
                                          : 'End Date')}
                                      .hideLabel=${this.hideLabel}
                                      .helpText=${this.endHelpText || this.helpText}
                                      .value=${this.getEndDateDisplayValue()}
                                      placeholder=${this.endPlaceholder}
                                      @terra-blur=${this.handleEndInputBlur}
                                      @keydown=${this.handleKeydown}
                                      name="end-date"
                                  >
                                      ${this.renderCalendarIcon()}
                                  </terra-input>
                                  ${this.renderCalendarContent()}
                              </terra-dropdown>
                          </div>
                      `
                    : html`
                          <terra-dropdown
                              ${ref(this.dropdownRef)}
                              placement="bottom-start"
                              distance="4"
                              @terra-show=${this.handleDropdownShow}
                              @terra-hide=${this.handleDropdownHide}
                              hoist
                          >
                              <terra-input
                                  slot="trigger"
                                  .label=${this.label}
                                  .hideLabel=${this.hideLabel}
                                  .helpText=${this.helpText}
                                  .value=${this.getDisplayValue()}
                                  placeholder=${this.placeholder}
                                  @terra-blur=${this.handleInputBlur}
                                  @keydown=${this.handleKeydown}
                                  name="date"
                              >
                                  ${this.renderCalendarIcon()}
                              </terra-input>
                              ${this.renderCalendarContent()}
                          </terra-dropdown>
                      `}
            </div>
        `
    }
}

declare global {
    interface HTMLElementTagNameMap {
        'terra-date-picker': TerraDatePicker
    }
}
