import { DatePipe } from '@angular/common';
import { Component, ChangeDetectionStrategy, Input, EventEmitter, Output } from '@angular/core';
import { DomainTaskCalendarService } from '@domain/task-calendar';
import { DisplayInfoDTO } from '@generated/swagger/eis-api';
import { DateAdapter } from '@ui/common';
import { BehaviorSubject, combineLatest } from 'rxjs';
import { map, withLatestFrom } from 'rxjs/operators';

@Component({
  selector: 'page-task-list',
  templateUrl: 'task-list.component.html',
  styleUrls: ['task-list.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
  providers: [DatePipe],
  standalone: false,
})
export class TaskListComponent {
  today = this.dateAdapter.today();

  /* @internal */
  items$ = new BehaviorSubject<DisplayInfoDTO[]>([]);

  @Input()
  get items() {
    return this.items$.value;
  }
  set items(value) {
    this.items$.next(value);
  }

  /* @internal */
  selected$ = new BehaviorSubject<Date>(new Date());

  @Input()
  get selected() {
    return this.selected$.value;
  }
  set selected(value) {
    if (this.selected !== value) {
      this.selected$.next(value);
    }
  }

  /* @internal */
  fetching$ = new BehaviorSubject<boolean>(true);

  @Input()
  get fetching() {
    return this.fetching$.value;
  }
  set fetching(value) {
    if (this.fetching !== value) {
      this.fetching$.next(value);
    }
  }

  isToday$ = this.selected$.pipe(
    map((selected) => this.dateAdapter.equals({ first: selected, second: this.today, precision: 'day' })),
  );

  overdueItems$ = combineLatest([this.items$, this.selected$]).pipe(
    map(([items, selectedDate]) => {
      const last7Days = this.dateAdapter.addCalendarDays(this.today, -7);
      return items.filter((item) => {
        const type = this.domainTaskCalendarService.getInfoType(item);
        const processingStatus = this.domainTaskCalendarService.getProcessingStatusList(item);
        if (type === 'Task' && processingStatus.includes('Overdue')) {
          return new Date(item.taskOverdueDate) >= last7Days;
        }
        return false;
      });
    }),
    withLatestFrom(this.selected$),
    map(([list, date]) =>
      list.filter((item) =>
        item?.successor
          ? this.dateAdapter.equals({
              first: new Date(item.publicationDate || item.taskDate),
              second: date,
              precision: 'day',
            })
          : item,
      ),
    ),
    map((list) => list.sort((a, b) => this.domainTaskCalendarService.moveRemovedToEnd(a, b))),
  );

  showOverdueItems$ = this.overdueItems$.pipe(
    withLatestFrom(this.isToday$),
    map(([items, today]) => today && items?.length > 0),
  );

  ongoingItems$ = combineLatest([this.items$, this.selected$]).pipe(
    map(([items, selectedDate]) =>
      // Filter Aufgaben die vor dem aktuellen Tag gestartet sind und nicht überfällig oder abgeschlossen sind
      items.filter((item) => {
        const type = this.domainTaskCalendarService.getInfoType(item);
        const processingStatus = this.domainTaskCalendarService.getProcessingStatusList(item);
        if (
          type === 'Task' &&
          (processingStatus.includes('InProcess') || processingStatus.includes('Approved')) &&
          !processingStatus.includes('Removed') &&
          !processingStatus.includes('Uncompleted') &&
          !processingStatus.includes('Overdue') &&
          !processingStatus.includes('Completed')
        ) {
          return new Date(item.publicationDate || item.taskDate) < this.today;
        }
        return false;
      }),
    ),
    withLatestFrom(this.selected$),
    map(([list, date]) =>
      list.filter((item) =>
        item?.successor
          ? this.dateAdapter.equals({
              first: new Date(item.publicationDate || item.taskDate),
              second: date,
              precision: 'day',
            })
          : item,
      ),
    ),
    map((list) =>
      this.domainTaskCalendarService.sort(list, ['Overdue', 'InProcess', 'Approved', 'Completed', 'Removed']),
    ),
    map((list) => list.sort((a, b) => this.domainTaskCalendarService.moveRemovedToEnd(a, b))),
  );

  showOngoingItems$ = this.ongoingItems$.pipe(
    withLatestFrom(this.isToday$),
    map(([items, today]) => today && items?.length > 0),
  );

  selectedItems$ = combineLatest([this.items$, this.selected$]).pipe(
    map(([items, date]) =>
      items.filter((item) =>
        this.dateAdapter.equals({
          first: this.domainTaskCalendarService.getDisplayInfoDate(item),
          second: date,
          precision: 'day',
        }),
      ),
    ),
    withLatestFrom(this.selected$),
    map(([list, date]) =>
      list.filter((item) =>
        item?.successor
          ? this.dateAdapter.equals({ first: new Date(item.publicationDate), second: date, precision: 'day' })
          : item,
      ),
    ),
    // Sortierung der aufgaben nach Rot => Gelb => Grau => Grün
    map((list) =>
      this.domainTaskCalendarService.sort(list, ['Overdue', 'InProcess', 'Approved', 'Completed', 'Removed']),
    ),
    map((list) => list.sort((a, b) => this.domainTaskCalendarService.moveRemovedToEnd(a, b))),
  );

  @Output()
  select = new EventEmitter<DisplayInfoDTO>();

  constructor(
    private dateAdapter: DateAdapter,
    private domainTaskCalendarService: DomainTaskCalendarService,
  ) {}
}
