// #region Imports
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
import { formatDateToIso, getDayKey, getWeekNumber } from '../../../../../Extensions/DateExtensions';
import { DateFormatter } from '../../../../../Intl/Formatters/DateFormatter';
import { Attribute } from '../../../../Decorators/AttributeDecorator';
import { Component } from '../../../../Decorators/ComponentDecorator';
import { HintElement } from '../../../Primitives/Hint/HintElement';
import { SchedulerViewBaseElement } from './Abstracts/SchedulerViewBaseElement';
import { ISchedulerMonthViewElementProps } from './ISchedulerMonthViewElementProps';
import { schedulerMonthViewElementTemplate } from './SchedulerMonthViewElementTemplate';
import { schedulerMonthViewElementCosmopolitanStyle } from './Themes/SchedulerMonthViewElement.Cosmopolitan';
import { schedulerMonthViewElementJoyStyle } from './Themes/SchedulerMonthViewElement.Joy';
import { schedulerMonthViewElementMemphisStyle } from './Themes/SchedulerMonthViewElement.Memphis';
// #endregion
/**
 * Gets the first day of the month for a given date.
 *
 * @internal
 */
function getStartOfMonth(date) {
    return new Date(date.getFullYear(), date.getMonth(), 1);
}
/**
 * Scheduler Month View - A calendar-style month view with event chips.
 *
 * @description
 * The Month view displays events in a traditional calendar grid layout with weeks as rows
 * and days as columns. Events are shown as compact chips within each day cell.
 * The view supports week numbers, adjacent month days, and highlighting.
 *
 * @name Scheduler Month View
 * @element mosaik-scheduler-month-view
 * @category Scheduler
 *
 * @slot - Default slot for event content
 *
 * @csspart container - The main container
 * @csspart header - The header row with day labels
 * @csspart header-cell - Individual day header cells (Sun, Mon, etc.)
 * @csspart week-number-header - The week number column header
 * @csspart body - The scrollable body area
 * @csspart week-row - A single week row
 * @csspart week-number - The week number cell
 * @csspart day-cell - Individual day cells
 * @csspart day-number - The day number within a cell
 * @csspart day-events - Container for event chips in a day
 * @csspart event-chip - Individual event chip
 *
 * @cssprop {Color} --scheduler-month-view-background-color - Background color of the view
 * @cssprop {Color} --scheduler-month-view-border-color - Border color
 * @cssprop {String} --scheduler-month-view-border-radius - Border radius
 * @cssprop {String} --scheduler-month-view-border-style - Border style
 * @cssprop {String} --scheduler-month-view-border-width - Border width
 * @cssprop {String} --scheduler-month-view-cell-min-height - Minimum height for day cells
 * @cssprop {String} --scheduler-month-view-day-number-font-size - Font size for day numbers
 * @cssprop {String} --scheduler-month-view-day-number-font-weight - Font weight for day numbers
 * @cssprop {String} --scheduler-month-view-event-chip-border-radius - Border radius for event chips
 * @cssprop {String} --scheduler-month-view-event-chip-font-size - Font size for event chip text
 * @cssprop {String} --scheduler-month-view-event-chip-height - Height of event chips
 * @cssprop {Color} --scheduler-month-view-foreground-color - Foreground/text color
 * @cssprop {String} --scheduler-month-view-gap - Gap between cells and elements
 * @cssprop {String} --scheduler-month-view-header-day-font-family - Font family for day headers
 * @cssprop {String} --scheduler-month-view-header-day-font-letter-spacing - Letter spacing for day headers
 * @cssprop {String} --scheduler-month-view-header-day-font-line-height - Line height for day headers
 * @cssprop {String} --scheduler-month-view-header-day-font-size - Font size for day headers
 * @cssprop {String} --scheduler-month-view-header-day-font-text-decoration - Text decoration for day headers
 * @cssprop {String} --scheduler-month-view-header-day-font-text-transform - Text transform for day headers
 * @cssprop {String} --scheduler-month-view-header-day-font-weight - Font weight for day headers
 * @cssprop {String} --scheduler-month-view-header-font-family - Font family for headers
 * @cssprop {String} --scheduler-month-view-header-font-letter-spacing - Letter spacing for headers
 * @cssprop {String} --scheduler-month-view-header-font-line-height - Line height for headers
 * @cssprop {String} --scheduler-month-view-header-font-size - Font size for headers
 * @cssprop {String} --scheduler-month-view-header-font-text-decoration - Text decoration for headers
 * @cssprop {String} --scheduler-month-view-header-font-text-transform - Text transform for headers
 * @cssprop {String} --scheduler-month-view-header-font-weight - Font weight for headers
 * @cssprop {String} --scheduler-month-view-header-weekday-font-family - Font family for weekday labels
 * @cssprop {String} --scheduler-month-view-header-weekday-font-letter-spacing - Letter spacing for weekday labels
 * @cssprop {String} --scheduler-month-view-header-weekday-font-line-height - Line height for weekday labels
 * @cssprop {String} --scheduler-month-view-header-weekday-font-size - Font size for weekday labels
 * @cssprop {String} --scheduler-month-view-header-weekday-font-text-decoration - Text decoration for weekday labels
 * @cssprop {String} --scheduler-month-view-header-weekday-font-text-transform - Text transform for weekday labels
 * @cssprop {String} --scheduler-month-view-header-weekday-font-weight - Font weight for weekday labels
 * @cssprop {String} --scheduler-month-view-padding-bottom - Bottom padding
 * @cssprop {String} --scheduler-month-view-padding-left - Left padding
 * @cssprop {String} --scheduler-month-view-padding-right - Right padding
 * @cssprop {String} --scheduler-month-view-padding-top - Top padding
 * @cssprop {Color} --scheduler-month-view-today-background-color - Background color for today's cell
 * @cssprop {Color} --scheduler-month-view-weekend-background-color - Background color for weekend cells
 *
 * @dependency {HintElement} - Used for "more events" indication
 *
 * @public
 */
let SchedulerMonthViewElement = class SchedulerMonthViewElement extends SchedulerViewBaseElement {
    // #region Fields
    _showWeekNumbers;
    _showAdjacent;
    _weeks;
    _weekdayHeaders;
    _eventsByDay;
    // #endregion
    // #region Ctor
    constructor() {
        super();
        this._showWeekNumbers = ISchedulerMonthViewElementProps.DEFAULTS.showWeekNumbers;
        this._showAdjacent = ISchedulerMonthViewElementProps.DEFAULTS.showAdjacent;
        this._weeks = [];
        this._weekdayHeaders = [];
        this._eventsByDay = new Map();
    }
    // #endregion
    // #region Properties
    /**
     * Returns the `is` property.
     *
     * @public
     * @static
     * @readonly
     */
    static get is() {
        return 'mosaik-scheduler-month-view';
    }
    /**
     * Gets the layout mode for this view.
     *
     * @public
     * @override
     * @readonly
     */
    get view() {
        return 'month';
    }
    /**
     * Gets or sets whether to show week numbers.
     *
     * @public
     * @attr
     */
    get showWeekNumbers() {
        return this._showWeekNumbers;
    }
    set showWeekNumbers(value) {
        if (this._showWeekNumbers !== value) {
            this._showWeekNumbers = value;
            this.requestUpdate('showWeekNumbers');
        }
    }
    /**
     * Gets or sets whether to show adjacent month days.
     *
     * @public
     * @attr
     */
    get showAdjacent() {
        return this._showAdjacent;
    }
    set showAdjacent(value) {
        if (this._showAdjacent !== value) {
            this._showAdjacent = value;
            this.requestUpdate('showAdjacent');
        }
    }
    /**
     * Gets the weeks data for rendering.
     *
     * @public
     * @readonly
     */
    get weeks() {
        return this._weeks;
    }
    /**
     * Gets the weekday headers.
     *
     * @public
     * @readonly
     */
    get weekdayHeaders() {
        return this._weekdayHeaders;
    }
    // #endregion
    // #region Methods
    /**
     * @public
     * @override
     */
    connectedCallback() {
        super.connectedCallback();
    }
    /**
     * Called after every update. Ensures the grid is built after all property bindings are applied.
     *
     * @protected
     * @override
     */
    updated(changedProperties) {
        super.updated(changedProperties);
        // Build grid on first update or when relevant properties change
        if (this._weeks.length === 0 ||
            changedProperties.has('firstDayOfWeek') ||
            changedProperties.has('startDate') ||
            changedProperties.has('weekdayFormat') ||
            changedProperties.has('locale')) {
            this.buildMonthGrid();
            this.positionEvents();
        }
        else if (changedProperties.has('collectedEvents')) {
            // Only re-position events if events changed but grid doesn't need rebuild
            this.positionEvents();
        }
    }
    /**
     * Handles click on a day cell.
     *
     * @param date - The date of the cell.
     * @internal
     */
    onDayCellClick(date) {
        const start = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
        const end = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 23, 59, 59);
        const dayKey = formatDateToIso(date);
        this.emitSelectRange(start, end, dayKey, true);
    }
    /**
     * Gets events for a specific day.
     *
     * @public
     * @param dayKey - The day key (YYYY-MM-DD).
     * @returns Array of events for that day.
     */
    getEventsForDay(dayKey) {
        return this._eventsByDay.get(dayKey) ?? [];
    }
    buildMonthGrid() {
        const currentMonth = getStartOfMonth(this.effectiveStartDate);
        const year = currentMonth.getFullYear();
        const month = currentMonth.getMonth();
        const firstDayOfWeek = this.firstDayOfWeek;
        // Build weekday headers using the same firstDayOfWeek as the grid
        this._weekdayHeaders = [];
        for (let i = 0; i < 7; i++) {
            const dayIndex = (firstDayOfWeek + i) % 7;
            // Create a date that falls on the desired day of week
            // Jan 7, 2024 is a Sunday (day 0), so Jan 7 + dayIndex gives the correct weekday
            const refDate = new Date(2024, 0, 7 + dayIndex);
            this._weekdayHeaders.push(DateFormatter.format(refDate, this.weekdayFormat, this.locale));
        }
        // Find the first day to display (may be from previous month)
        const firstDayOfMonth = new Date(year, month, 1);
        const dayOfWeek = firstDayOfMonth.getDay();
        const daysToSubtract = (dayOfWeek - firstDayOfWeek + 7) % 7;
        const gridStart = new Date(year, month, 1 - daysToSubtract);
        // Build 6 weeks (42 days) to ensure we cover all cases
        this._weeks = [];
        const today = new Date();
        const todayKey = getDayKey(today);
        for (let week = 0; week < 6; week++) {
            const weekDays = [];
            const weekStart = new Date(gridStart);
            weekStart.setDate(gridStart.getDate() + week * 7);
            for (let day = 0; day < 7; day++) {
                const date = new Date(weekStart);
                date.setDate(weekStart.getDate() + day);
                const isCurrentMonth = date.getMonth() === month;
                const dayKey = getDayKey(date);
                weekDays.push({
                    date,
                    dayNumber: date.getDate(),
                    isCurrentMonth,
                    isToday: dayKey === todayKey,
                    isWeekend: this.isWeekend(date),
                    isBlackout: this.isBlackoutDate(date),
                    isSpecial: this.isSpecialDate(date),
                    events: []
                });
            }
            const weekNumber = getWeekNumber(weekDays[0].date);
            this._weeks.push({
                weekNumber,
                days: weekDays
            });
        }
        this.requestUpdate();
    }
    positionEvents() {
        this._eventsByDay = new Map();
        for (const event of this.collectedEvents) {
            const dayKey = getDayKey(event.startTime);
            if (!this._eventsByDay.has(dayKey)) {
                this._eventsByDay.set(dayKey, []);
            }
            this._eventsByDay.get(dayKey).push({
                eventKey: event.eventKey,
                startTime: event.startTime,
                endTime: event.endTime,
                element: event.element
            });
        }
        // Update the weeks data with events
        for (const week of this._weeks) {
            for (const day of week.days) {
                const dayKey = getDayKey(day.date);
                day.events = this._eventsByDay.get(dayKey) ?? [];
            }
        }
        this.requestUpdate();
    }
};
__decorate([
    Attribute({ type: Boolean, useDefault: true }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [Boolean])
], SchedulerMonthViewElement.prototype, "showWeekNumbers", null);
__decorate([
    Attribute({ type: Boolean, useDefault: true }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [Boolean])
], SchedulerMonthViewElement.prototype, "showAdjacent", null);
SchedulerMonthViewElement = __decorate([
    Component({
        selector: 'mosaik-scheduler-month-view',
        template: schedulerMonthViewElementTemplate,
        themes: {
            joy: schedulerMonthViewElementJoyStyle,
            cosmopolitan: schedulerMonthViewElementCosmopolitanStyle,
            memphis: schedulerMonthViewElementMemphisStyle
        },
        imports: [
            HintElement
        ]
    }),
    __metadata("design:paramtypes", [])
], SchedulerMonthViewElement);
export { SchedulerMonthViewElement };
//# sourceMappingURL=SchedulerMonthViewElement.js.map