import { Component } from '@angular/core';
import { DatePipe } from '@shared/pipes/date.pipe';
import { NotificationsService } from '@services/notifications.service';
import { Notification } from '@red/domain';
import { distinctUntilChanged, map } from 'rxjs/operators';
import { Observable } from 'rxjs';
import { isToday, shareLast, trackByFactory } from '@iqser/common-ui/lib/utils';
import dayjs, { Dayjs } from 'dayjs';
import { TranslateService } from '@ngx-translate/core';

interface NotificationsGroup {
    date: string;
    notifications: Notification[];
}

export function isOlderThan(date: string | Date | Dayjs, years: number) {
    return dayjs(date).year() <= dayjs(Date.now()).subtract(years, 'year').year();
}

function chronologically(first: string, second: string) {
    return dayjs(first).isAfter(second) ? -1 : 1;
}

@Component({
    selector: 'redaction-notifications',
    templateUrl: './notifications.component.html',
    styleUrls: ['./notifications.component.scss'],
})
export class NotificationsComponent {
    readonly hasUnreadNotifications$: Observable<boolean>;
    readonly groupedNotifications$: Observable<NotificationsGroup[]>;
    readonly trackBy = trackByFactory();

    constructor(
        private readonly _notificationsService: NotificationsService,
        private readonly _datePipe: DatePipe,
        private readonly _translateService: TranslateService,
    ) {
        this.groupedNotifications$ = this._notificationsService.all$.pipe(map(notifications => this.#groupNotifications(notifications)));
        this.hasUnreadNotifications$ = this.#hasUnreadNotifications$;
    }

    get #hasUnreadNotifications$(): Observable<boolean> {
        return this._notificationsService.all$.pipe(
            map(notifications => notifications.filter(n => !n.readDate).length > 0),
            distinctUntilChanged(),
            shareLast(),
        );
    }

    async markRead(notifications: Notification[] = this._notificationsService.all, isRead = true): Promise<void> {
        if (!notifications.find(notification => !!notification.readDate !== isRead)) {
            // If no notification changes status after the request, abort
            return;
        }

        const notificationsIds = notifications.map(n => n.id);
        await this._notificationsService.toggleNotificationRead(notificationsIds, isRead);
    }

    #groupNotifications(notifications: Notification[]): NotificationsGroup[] {
        const todayTranslation = this._translateService.instant('today');
        const groupedMap = notifications.groupBy(n => {
            if (isOlderThan(n.creationDate, 2)) {
                return dayjs(n.creationDate).year().toString();
            } else if (isOlderThan(n.creationDate, 1)) {
                return dayjs(n.creationDate).format('YYYY-MM');
            }

            return n.creationDate.split('T')[0];
        });

        const sortedGroups = [...groupedMap.entries()].sort(([aDate], [bDate]) => chronologically(aDate, bDate));
        return sortedGroups.map(([date, _notifications]) => ({
            date: isToday(date) ? todayTranslation : this._datePipe.transform(date, 'sophisticatedDate'),
            notifications: [..._notifications].sort((a, b) => chronologically(a.creationDate, b.creationDate)),
        }));
    }
}
