import { TuiDayRange, TUI_FIRST_DAY, TUI_LAST_DAY, TuiDay, TuiMonth } from '@taiga-ui/cdk/date-time';
import { __decorate } from 'tslib';
import { AsyncPipe, NgForOf, NgIf } from '@angular/common';
import * as i0 from '@angular/core';
import { inject, ChangeDetectorRef, EventEmitter, Component, ChangeDetectionStrategy, Input, Output } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { TUI_FALSE_HANDLER } from '@taiga-ui/cdk/constants';
import { tuiWatch } from '@taiga-ui/cdk/observables';
import { TuiMapperPipe } from '@taiga-ui/cdk/pipes/mapper';
import { TUI_IS_MOBILE } from '@taiga-ui/cdk/tokens';
import { tuiIsString, tuiNullableSame, tuiPure } from '@taiga-ui/cdk/utils/miscellaneous';
import { TUI_COMMON_ICONS, tuiAsAuxiliary } from '@taiga-ui/core/tokens';
import { TUI_TEXTFIELD_OPTIONS } from '@taiga-ui/core/components/textfield';
import { tuiCalendarSheetOptionsProvider, TuiCalendar } from '@taiga-ui/core/components/calendar';
import * as i1 from '@taiga-ui/core/components/data-list';
import { TuiDataList } from '@taiga-ui/core/components/data-list';
import { TuiIcon } from '@taiga-ui/core/components/icon';
import { TUI_OTHER_DATE_TEXT, TUI_CALENDAR_DATE_STREAM } from '@taiga-ui/kit/tokens';

const calculateDisabledItemHandler = (disabledItemHandler, value, minLength) => (item) => {
    if (!value || value instanceof TuiDayRange || !minLength) {
        return disabledItemHandler(item);
    }
    const negativeMinLength = Object.fromEntries(Object.entries(minLength).map(([key, value]) => [key, -value]));
    const disabledBefore = value.append(negativeMinLength).append({ day: 1 });
    const disabledAfter = value.append(minLength).append({ day: -1 });
    const inDisabledRange = disabledBefore.dayBefore(item) && disabledAfter.dayAfter(item);
    return inDisabledRange || disabledItemHandler(item);
};

const TUI_DAY_CAPS_MAPPER = (current, value, maxLength, backwards) => {
    if (
    // TODO(v5): replace with `if (!(value instanceof TuiDay) || !maxLength)` (backward compatibility)
    (value instanceof TuiDayRange && !value.isSingleDay) ||
        !value ||
        !maxLength) {
        return backwards ? current || TUI_FIRST_DAY : current || TUI_LAST_DAY;
    }
    const negativeMaxLength = Object.fromEntries(Object.entries(maxLength).map(([key, value]) => [key, -value]));
    // TODO(v5): `value instanceof TuiDay` always `true`
    const from = value instanceof TuiDay ? value : value.from;
    const dateShift = from
        .append(backwards ? negativeMaxLength : maxLength)
        .append({ day: !backwards ? -1 : 1 });
    if (backwards) {
        return dateShift.dayBefore(current || TUI_FIRST_DAY)
            ? current || TUI_FIRST_DAY
            : dateShift;
    }
    if (!current) {
        return dateShift;
    }
    return dateShift.dayAfter(current) ? current : dateShift;
};

class TuiCalendarRange {
    constructor() {
        /**
         * @deprecated use `item`
         */
        this.selectedPeriod = null;
        this.cdr = inject(ChangeDetectorRef);
        this.currentValue = null;
        this.previousValue = null;
        this.hoveredItem = null;
        this.month = TuiMonth.currentLocal();
        this.otherDateText$ = inject(TUI_OTHER_DATE_TEXT);
        this.icons = inject(TUI_COMMON_ICONS);
        this.capsMapper = TUI_DAY_CAPS_MAPPER;
        this.mobile = inject(TUI_IS_MOBILE);
        this.options = inject(TUI_TEXTFIELD_OPTIONS);
        this.disabledItemHandler = TUI_FALSE_HANDLER;
        this.markerHandler = null;
        this.items = [];
        this.listSize = this.options.size();
        this.min = TUI_FIRST_DAY;
        this.max = TUI_LAST_DAY;
        this.minLength = null;
        this.maxLength = null;
        this.item = null;
        this.valueChange = new EventEmitter();
        this.itemChange = new EventEmitter();
        this.monthOffset = (value, month) => value.append({ month });
        this.mapper = (items, min, max, minLength, otherDateText) => [
            ...items.filter((item) => (minLength === null ||
                item.range.from
                    .append(minLength)
                    .append({ day: -1 })
                    .daySameOrBefore(item.range.to)) &&
                (min === null || item.range.to.daySameOrAfter(min)) &&
                (max === null || item.range.from.daySameOrBefore(max))),
            otherDateText || '',
        ];
        inject(TUI_CALENDAR_DATE_STREAM, { optional: true })
            ?.pipe(tuiWatch(), takeUntilDestroyed())
            .subscribe((value) => {
            this.currentValue = value;
            this.initDefaultViewedMonth();
        });
    }
    set valueSetter(value) {
        this.currentValue = value;
    }
    set defaultViewedMonth(month) {
        if (!this.currentValue) {
            this.month = month;
        }
    }
    set value(value) {
        this.cdr.markForCheck();
        this.currentValue = value;
        this.initDefaultViewedMonth();
    }
    get defaultViewedMonth() {
        return this.month;
    }
    /**
     * @deprecated use `item`
     */
    get selectedActivePeriod() {
        return this.selectedPeriod;
    }
    /**
     * @deprecated use `item`
     */
    set selectedActivePeriod(period) {
        this.selectedPeriod = period;
    }
    ngOnChanges() {
        if (!this.currentValue) {
            this.initDefaultViewedMonth();
        }
    }
    ngOnInit() {
        this.initDefaultViewedMonth();
    }
    get calculatedDisabledItemHandler() {
        return this.calculateDisabledItemHandler(this.disabledItemHandler, this.currentValue, this.minLength);
    }
    onEsc(event) {
        if (event.key !== 'Escape' || !(this.currentValue instanceof TuiDay)) {
            return;
        }
        event.stopPropagation();
        this.currentValue = this.previousValue;
    }
    isItemActive(item) {
        const { activePeriod } = this;
        return ((tuiIsString(item) && activePeriod === null) ||
            activePeriod === item ||
            activePeriod?.toString() === item.toString());
    }
    onItemSelect(item) {
        if (!tuiIsString(item)) {
            this.selectedActivePeriod = item;
            this.itemChange.emit(item);
            this.updateValue(item.range.dayLimit(this.min, this.max));
        }
        else if (this.activePeriod !== null) {
            this.selectedActivePeriod = null;
            this.itemChange.emit(null);
            this.updateValue(null);
        }
        this.initDefaultViewedMonth();
    }
    onMonthChange(month) {
        this.month = month;
    }
    onDayClick(day) {
        this.previousValue = this.currentValue;
        this.selectedActivePeriod = null;
        if (this.currentValue instanceof TuiDay) {
            const range = TuiDayRange.sort(this.currentValue, day);
            this.currentValue = range;
            this.itemChange.emit(this.findItemByDayRange(range));
            this.updateValue(range);
        }
        else {
            this.currentValue = day;
        }
    }
    updateValue(value) {
        this.currentValue = value;
        this.valueChange.emit(value);
    }
    get activePeriod() {
        return (this.item ??
            this.selectedActivePeriod ??
            (this.items.find((item) => tuiNullableSame(this.currentValue instanceof TuiDay
                ? new TuiDayRange(this.currentValue, this.currentValue)
                : this.currentValue, item.range, (a, b) => a.from.daySame(b.from.dayLimit(this.min, this.max)) &&
                a.to.daySame(b.to.dayLimit(this.min, this.max)))) ||
                null));
    }
    calculateDisabledItemHandler(disabledItemHandler, value, minLength) {
        return calculateDisabledItemHandler(disabledItemHandler, value, minLength);
    }
    initDefaultViewedMonth() {
        if (this.currentValue instanceof TuiDay) {
            this.month = this.currentValue;
        }
        else if (this.currentValue) {
            this.month = this.items.length
                ? this.currentValue.to
                : this.currentValue.from;
        }
        else if (this.max && this.month.monthSameOrAfter(this.max)) {
            this.month = this.items.length ? this.max : this.max.append({ month: -1 });
        }
        else if (this.min && this.month.monthSameOrBefore(this.min)) {
            this.month = this.min;
        }
    }
    findItemByDayRange(dayRange) {
        return this.items.find((item) => dayRange.daySame(item.range)) ?? null;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TuiCalendarRange, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: TuiCalendarRange, isStandalone: true, selector: "tui-calendar-range", inputs: { disabledItemHandler: "disabledItemHandler", markerHandler: "markerHandler", items: "items", listSize: "listSize", min: "min", max: "max", minLength: "minLength", maxLength: "maxLength", item: "item", valueSetter: ["value", "valueSetter"], defaultViewedMonth: "defaultViewedMonth" }, outputs: { valueChange: "valueChange", itemChange: "itemChange" }, host: { listeners: { "document:keydown.capture": "onEsc($event)" }, properties: { "class._mobile": "mobile" } }, providers: [
            tuiAsAuxiliary(TuiCalendarRange),
            tuiCalendarSheetOptionsProvider({ rangeMode: true }),
        ], usesOnChanges: true, ngImport: i0, template: "<tui-calendar\n    automation-id=\"tui-calendar-range__calendar\"\n    [class.t-calendar]=\"!mobile\"\n    [disabledItemHandler]=\"calculatedDisabledItemHandler\"\n    [markerHandler]=\"markerHandler\"\n    [max]=\"max | tuiMapper: capsMapper : currentValue : maxLength : false\"\n    [maxViewedMonth]=\"items.length || mobile ? null : (defaultViewedMonth | tuiMapper: monthOffset : -1)\"\n    [min]=\"min | tuiMapper: capsMapper : currentValue : maxLength : true\"\n    [month]=\"defaultViewedMonth\"\n    [showAdjacent]=\"!!items.length || mobile\"\n    [value]=\"currentValue\"\n    [(hoveredItem)]=\"hoveredItem\"\n    (dayClick)=\"onDayClick($event)\"\n    (monthChange)=\"onMonthChange($event)\"\n/>\n<tui-calendar\n    *ngIf=\"!items.length && !mobile; else presets\"\n    [disabledItemHandler]=\"calculatedDisabledItemHandler\"\n    [markerHandler]=\"markerHandler\"\n    [max]=\"max | tuiMapper: capsMapper : currentValue : maxLength : false\"\n    [min]=\"min | tuiMapper: capsMapper : currentValue : maxLength : true\"\n    [minViewedMonth]=\"defaultViewedMonth | tuiMapper: monthOffset : 1\"\n    [month]=\"defaultViewedMonth | tuiMapper: monthOffset : 1\"\n    [showAdjacent]=\"false\"\n    [value]=\"currentValue\"\n    [(hoveredItem)]=\"hoveredItem\"\n    (dayClick)=\"onDayClick($event)\"\n    (monthChange)=\"onMonthChange($event.append({month: -1}))\"\n/>\n<ng-template #presets>\n    <tui-data-list\n        *ngIf=\"!mobile\"\n        automation-id=\"tui-calendar-range__menu\"\n        role=\"menu\"\n        [size]=\"listSize\"\n        [style.flex]=\"1\"\n    >\n        <button\n            *ngFor=\"let item of items | tuiMapper: mapper : min : max : minLength : (otherDateText$ | async)\"\n            automation-id=\"tui-calendar-range__menu__item\"\n            role=\"menuitemradio\"\n            tuiOption\n            type=\"button\"\n            [attr.aria-checked]=\"isItemActive(item)\"\n            (click)=\"onItemSelect(item)\"\n            (pointerdown.prevent.zoneless)=\"(0)\"\n        >\n            {{ item }}\n            <tui-icon\n                *ngIf=\"isItemActive(item)\"\n                automation-id=\"tui-calendar-range__checkmark\"\n                [icon]=\"icons.check\"\n                [style.font-size.rem]=\"1\"\n            />\n        </button>\n    </tui-data-list>\n</ng-template>\n", styles: [":host:not(._mobile){display:flex;min-inline-size:30rem}.t-calendar{border-inline-end:1px solid var(--tui-border-normal)}\n"], dependencies: [{ kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "directive", type: NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: TuiCalendar, selector: "tui-calendar", inputs: ["month", "disabledItemHandler", "min", "max", "minViewedMonth", "maxViewedMonth", "hoveredItem", "showAdjacent", "markerHandler", "value", "initialView"], outputs: ["dayClick", "monthChange", "hoveredItemChange"] }, { kind: "component", type: i1.TuiDataListComponent, selector: "tui-data-list", inputs: ["emptyContent", "size"] }, { kind: "component", type: i1.TuiOption, selector: "button[tuiOption]:not([new]), a[tuiOption]:not([new]), label[tuiOption]:not([new])", inputs: ["disabled", "value"] }, { kind: "component", type: TuiIcon, selector: "tui-icon", inputs: ["icon", "background"] }, { kind: "pipe", type: TuiMapperPipe, name: "tuiMapper" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
__decorate([
    tuiPure
], TuiCalendarRange.prototype, "calculateDisabledItemHandler", null);
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TuiCalendarRange, decorators: [{
            type: Component,
            args: [{ standalone: true, selector: 'tui-calendar-range', imports: [AsyncPipe, NgForOf, NgIf, TuiCalendar, TuiDataList, TuiIcon, TuiMapperPipe], changeDetection: ChangeDetectionStrategy.OnPush, providers: [
                        tuiAsAuxiliary(TuiCalendarRange),
                        tuiCalendarSheetOptionsProvider({ rangeMode: true }),
                    ], host: {
                        '[class._mobile]': 'mobile',
                        '(document:keydown.capture)': 'onEsc($event)',
                    }, template: "<tui-calendar\n    automation-id=\"tui-calendar-range__calendar\"\n    [class.t-calendar]=\"!mobile\"\n    [disabledItemHandler]=\"calculatedDisabledItemHandler\"\n    [markerHandler]=\"markerHandler\"\n    [max]=\"max | tuiMapper: capsMapper : currentValue : maxLength : false\"\n    [maxViewedMonth]=\"items.length || mobile ? null : (defaultViewedMonth | tuiMapper: monthOffset : -1)\"\n    [min]=\"min | tuiMapper: capsMapper : currentValue : maxLength : true\"\n    [month]=\"defaultViewedMonth\"\n    [showAdjacent]=\"!!items.length || mobile\"\n    [value]=\"currentValue\"\n    [(hoveredItem)]=\"hoveredItem\"\n    (dayClick)=\"onDayClick($event)\"\n    (monthChange)=\"onMonthChange($event)\"\n/>\n<tui-calendar\n    *ngIf=\"!items.length && !mobile; else presets\"\n    [disabledItemHandler]=\"calculatedDisabledItemHandler\"\n    [markerHandler]=\"markerHandler\"\n    [max]=\"max | tuiMapper: capsMapper : currentValue : maxLength : false\"\n    [min]=\"min | tuiMapper: capsMapper : currentValue : maxLength : true\"\n    [minViewedMonth]=\"defaultViewedMonth | tuiMapper: monthOffset : 1\"\n    [month]=\"defaultViewedMonth | tuiMapper: monthOffset : 1\"\n    [showAdjacent]=\"false\"\n    [value]=\"currentValue\"\n    [(hoveredItem)]=\"hoveredItem\"\n    (dayClick)=\"onDayClick($event)\"\n    (monthChange)=\"onMonthChange($event.append({month: -1}))\"\n/>\n<ng-template #presets>\n    <tui-data-list\n        *ngIf=\"!mobile\"\n        automation-id=\"tui-calendar-range__menu\"\n        role=\"menu\"\n        [size]=\"listSize\"\n        [style.flex]=\"1\"\n    >\n        <button\n            *ngFor=\"let item of items | tuiMapper: mapper : min : max : minLength : (otherDateText$ | async)\"\n            automation-id=\"tui-calendar-range__menu__item\"\n            role=\"menuitemradio\"\n            tuiOption\n            type=\"button\"\n            [attr.aria-checked]=\"isItemActive(item)\"\n            (click)=\"onItemSelect(item)\"\n            (pointerdown.prevent.zoneless)=\"(0)\"\n        >\n            {{ item }}\n            <tui-icon\n                *ngIf=\"isItemActive(item)\"\n                automation-id=\"tui-calendar-range__checkmark\"\n                [icon]=\"icons.check\"\n                [style.font-size.rem]=\"1\"\n            />\n        </button>\n    </tui-data-list>\n</ng-template>\n", styles: [":host:not(._mobile){display:flex;min-inline-size:30rem}.t-calendar{border-inline-end:1px solid var(--tui-border-normal)}\n"] }]
        }], ctorParameters: function () { return []; }, propDecorators: { disabledItemHandler: [{
                type: Input
            }], markerHandler: [{
                type: Input
            }], items: [{
                type: Input
            }], listSize: [{
                type: Input
            }], min: [{
                type: Input
            }], max: [{
                type: Input
            }], minLength: [{
                type: Input
            }], maxLength: [{
                type: Input
            }], item: [{
                type: Input
            }], valueChange: [{
                type: Output
            }], itemChange: [{
                type: Output
            }], valueSetter: [{
                type: Input,
                args: ['value']
            }], defaultViewedMonth: [{
                type: Input
            }], calculateDisabledItemHandler: [] } });

class TuiDayRangePeriod {
    constructor(range, name, content) {
        this.range = range;
        this.name = name;
        this.content = content;
    }
    toString() {
        return this.name;
    }
}
function tuiCreateDefaultDayRangePeriods(periodTitles = [
    'For all the time',
    'Today',
    'Yesterday',
    'Current week',
    'Current month',
    'Previous month',
]) {
    const today = TuiDay.currentLocal();
    const yesterday = today.append({ day: -1 });
    const startOfWeek = today.append({ day: -today.dayOfWeek() });
    const endOfWeek = startOfWeek.append({ day: 6 });
    const startOfMonth = today.append({ day: 1 - today.day });
    const endOfMonth = startOfMonth.append({ month: 1, day: -1 });
    const startOfLastMonth = startOfMonth.append({ month: -1 });
    return [
        new TuiDayRangePeriod(new TuiDayRange(TUI_FIRST_DAY, today), periodTitles[0]),
        new TuiDayRangePeriod(new TuiDayRange(today, today), periodTitles[1]),
        new TuiDayRangePeriod(new TuiDayRange(yesterday, yesterday), periodTitles[2]),
        new TuiDayRangePeriod(new TuiDayRange(startOfWeek, endOfWeek), periodTitles[3]),
        new TuiDayRangePeriod(new TuiDayRange(startOfMonth, endOfMonth), periodTitles[4]),
        new TuiDayRangePeriod(new TuiDayRange(startOfLastMonth, startOfMonth.append({ day: -1 })), periodTitles[5]),
    ];
}

/**
 * Generated bundle index. Do not edit.
 */

export { TUI_DAY_CAPS_MAPPER, TuiCalendarRange, TuiDayRangePeriod, calculateDisabledItemHandler, tuiCreateDefaultDayRangePeriods };
//# sourceMappingURL=taiga-ui-kit-components-calendar-range.mjs.map
