import {
  ChangeDetectionStrategy,
  Component,
  DestroyRef,
  effect,
  EventEmitter,
  inject,
  OnInit,
  signal
} from '@angular/core';
import {
  SideNavCompanionBarComponent
} from "../sidenav/_components/side-nav-companion-bar/side-nav-companion-bar.component";
import {TranslocoDirective} from "@jsverse/transloco";
import {ActivatedRoute} from "@angular/router";
import {AnnotationService} from "../_services/annotation.service";
import {FilterUtilitiesService} from "../shared/_services/filter-utilities.service";
import {Annotation} from "../book-reader/_models/annotations/annotation";
import {Pagination} from "../_models/pagination";
import {takeUntilDestroyed} from "@angular/core/rxjs-interop";
import {map, tap} from "rxjs/operators";
import {AnnotationFilterSettings} from "../metadata-filter/filter-settings";
import {
  AnnotationsFilter,
  AnnotationsFilterField,
  AnnotationsSortField
} from "../_models/metadata/v2/annotations-filter";
import {MetadataService} from "../_services/metadata.service";
import {FilterStatement} from "../_models/metadata/v2/filter-statement";
import {FilterEvent} from "../_models/metadata/series-filter";
import {DecimalPipe} from "@angular/common";
import {CardDetailLayoutComponent} from "../cards/card-detail-layout/card-detail-layout.component";
import {
  AnnotationCardComponent
} from "../book-reader/_components/_annotations/annotation-card/annotation-card.component";
import {BulkOperationsComponent} from "../cards/bulk-operations/bulk-operations.component";
import {BulkSelectionService} from "../cards/bulk-selection.service";
import {User} from "../_models/user/user";
import {ActionItem} from "../_models/actionables/action-item";
import {Action} from "../_models/actionables/action";
import {ActionResult} from "../_models/actionables/action-result";

@Component({
  selector: 'app-all-annotations',
  imports: [
    SideNavCompanionBarComponent,
    TranslocoDirective,
    DecimalPipe,
    CardDetailLayoutComponent,
    AnnotationCardComponent,
    BulkOperationsComponent
  ],
  templateUrl: './all-annotations.component.html',
  styleUrl: './all-annotations.component.scss',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class AllAnnotationsComponent implements OnInit {

  private readonly destroyRef = inject(DestroyRef);
  private readonly annotationsService = inject(AnnotationService);
  private readonly route = inject(ActivatedRoute);
  private readonly filterUtilityService = inject(FilterUtilitiesService);
  private readonly metadataService = inject(MetadataService);
  public readonly bulkSelectionService = inject(BulkSelectionService);

  isLoading = signal(true);
  annotations = signal<Annotation[]>([]);
  pagination = signal<Pagination>({
    currentPage: 0,
    itemsPerPage: 0,
    totalItems: 0,
    totalPages: 0
  });
  filterActive = signal(false);
  filter = signal<AnnotationsFilter | undefined>(undefined);

  filterSettings: AnnotationFilterSettings = new AnnotationFilterSettings();
  trackByIdentity = (idx: number, item: Annotation) => `${item.id}`;
  refresh: EventEmitter<void> = new EventEmitter();
  filterOpen: EventEmitter<boolean> = new EventEmitter();


  constructor() {
    effect(() => {
      const event = this.annotationsService.events();
      if (!event) return;

      switch (event.type) {
        case 'delete':
          this.annotations.update(x => x.filter(a => a.id !== event.annotation.id));
      }
    });

    effect(() => {
      this.annotations();
      this.bulkSelectionService.deselectAll();
    });

    this.bulkSelectionService.registerDataSource('annotations', () => this.annotations());
    this.bulkSelectionService.registerShouldRender(this.shouldRender.bind(this));
    this.bulkSelectionService.registerPostAction((result: ActionResult<Annotation[]>) => {
      const updatedEntities = result.entity;
      if (updatedEntities == null || updatedEntities.length === 0) return;

      let updatedItems: Annotation[] = [];
      switch (result.effect) {
        case "update":
          updatedItems = this.annotations().map(item => {
            const updated = updatedEntities.find(u => u.id === item.id);
            return updated ? { ...updated } : item;
          });
          this.annotations.set([...updatedItems]);
          break;
        case "remove":
          const removedIds = new Set(updatedEntities.map(u => u.id));

          const remainingItems = this.annotations().filter(
            item => !removedIds.has(item.id)
          );

          this.annotations.set([...remainingItems]);
          break;
        case "reload":
        case "none":
          break;
      }
    });
  }

  ngOnInit() {
    this.route.data.pipe(
      takeUntilDestroyed(this.destroyRef),
      map(data => data['filter'] as AnnotationsFilter | null | undefined),
      tap(filter => {
        if (!filter) {
          filter = this.metadataService.createDefaultFilterDto('annotation');
          filter.statements.push(this.metadataService.createDefaultFilterStatement('annotation') as FilterStatement<AnnotationsFilterField>);
        }

        this.filter.set(filter);
        this.filterSettings.presetsV2 = this.filter();
        this.loadData(this.filter())
      }),
    ).subscribe();
  }


  exportFilter() {
    const filter = this.filter();
    if (!filter) return;

    this.annotationsService.exportFilter(filter).subscribe();
  }

  shouldRender = (action: ActionItem<Annotation>, entity: Annotation, user: User) => {
    switch (action.action) {
      case Action.Delete:
        const selectedIndices = this.bulkSelectionService.getSelectedCardsForSource('annotations');
        const selectedAnnotations = this.annotations().filter((_, idx) => selectedIndices.includes(idx+''));
        return selectedAnnotations.find(a => a.ownerUsername !== user.username) === undefined;
    }

    return true;
  }

  private loadData(filter?: AnnotationsFilter) {
    if (!filter) {
      filter = this.metadataService.createDefaultFilterDto('annotation');
      filter.statements.push(this.metadataService.createDefaultFilterStatement('annotation') as FilterStatement<AnnotationsFilterField>);
    }

    this.annotationsService.getAllAnnotationsFiltered(filter).pipe(
      tap(a => {
        this.annotations.set(a.result);
        this.pagination.set(a.pagination);
      }),
      tap(() => this.isLoading.set(false)),
    ).subscribe();
  }

  updateFilter(data: FilterEvent<AnnotationsFilterField, AnnotationsSortField>) {
    if (!data.filterV2) {
      return;
    }

    if (!data.isFirst) {
      this.filterUtilityService.updateUrlFromFilter(data.filterV2).pipe(
        takeUntilDestroyed(this.destroyRef),
        tap(() => this.filter.set(data.filterV2)),
        tap(() => this.loadData(this.filter()))
      ).subscribe();
      return;
    }

    this.filter.set(data.filterV2);
  }
}
