/* eslint-disable @typescript-eslint/member-ordering */
import { FlatTreeControl } from '@angular/cdk/tree';
import {
  ChangeDetectionStrategy,
  Component,
  OnDestroy,
  OnInit,
  ViewChild
} from '@angular/core';
import { MatPaginator, PageEvent } from '@angular/material/paginator';
import {
  MatTreeFlatDataSource,
  MatTreeFlattener
} from '@angular/material/tree';
import {
  BehaviorSubject,
  map,
  shareReplay,
  Subscription,
  switchMap,
  tap
} from 'rxjs';

import { AnomaliesService } from '../anomalies.service';
import { Anomaly } from '../../../core/data-access/graphql/generated/generated';

interface AnomalyNode {
  name: string;
  anomalyId: string;
  anomaly: Anomaly;
  children?: AnomalyNode[];
}

interface AnomalyFlatNode {
  childCount: number;
  expandable: boolean;
  name: string;
  anomalyId: string;
  anomaly: Anomaly;
  level: number;
}

@Component({
    selector: 'dks-anomaly-tree',
    templateUrl: './anomaly-tree.component.html',
    styleUrls: ['./anomaly-tree.component.scss'],
    host: {
      class: 'flex flex-col h-full',
    },
    changeDetection: ChangeDetectionStrategy.OnPush,
    standalone: false
})
export class AnomalyTreeComponent implements OnInit, OnDestroy {
  @ViewChild(MatPaginator, { static: true }) private paginator!: MatPaginator;
  pageSize = 10;
  private _transformer = (node: AnomalyNode, level: number) => {
    return {
      childCount: node.children?.length || 0,
      expandable: !!node.children && node.children.length > 0,
      name: node.name,
      level: level,
      anomalyId: node.anomalyId,
      anomaly: node.anomaly,
    };
  };

  treeControl = new FlatTreeControl<AnomalyFlatNode>(
    (node) => node.level,
    (node) => node.expandable
  );

  treeFlattener = new MatTreeFlattener(
    this._transformer,
    (node) => node.level,
    (node) => node.expandable,
    (node) => node.children
  );

  private prevCursor = '';
  private nextCursor = '';
  private subscription = new Subscription();
  private cursor$ = new BehaviorSubject<string>(this.nextCursor);
  private paginatedGroupedAnomalies$ = this.cursor$.pipe(
    tap((cursor) => {
      if (!cursor) {
        this.prevCursor = '';
        this.nextCursor = '';
        this.paginator.firstPage();
      }
    }),
    switchMap((cursor) =>
      this.anomaliesService.getGroupedAnomaliesByPage(cursor, this.pageSize)
    ),
    tap(({ prevCursor, endCursor }) => {
      this.prevCursor = prevCursor;
      this.nextCursor = endCursor;
    }),
    shareReplay(1)
  );

  totalCount$ = this.paginatedGroupedAnomalies$.pipe(
    map(({ totalCount }) => totalCount)
  );

  anomalies$ = this.paginatedGroupedAnomalies$.pipe(
    map(({ nodes }) =>
      nodes?.map(({ anomalies }) => ({
        name: anomalies[0].groupDescription,
        anomalyId: '',
        anomaly: {} as Anomaly,
        children: anomalies.map((anomaly) => ({
          name: anomaly.description,
          anomalyId: anomaly.id,
          anomaly,
        })),
      }))
    ),
    tap((groupedAnomalies) => (this.dataSource.data = groupedAnomalies ?? []))
  );

  dataSource = new MatTreeFlatDataSource(this.treeControl, this.treeFlattener);

  constructor(private readonly anomaliesService: AnomaliesService) {
    this.dataSource.data;
  }

  ngOnInit(): void {
    this.subscription.add(
      this.anomaliesService.anomaliesRefresh$
        .pipe(tap(() => this.cursor$.next('')))
        .subscribe()
    );
  }

  ngOnDestroy(): void {
    this.subscription.unsubscribe();
  }

  setAnomalyToSleep(anomalyId: string): void {
    this.anomaliesService.setAnomalyToSleep(anomalyId);
  }

  acceptAnomaly(anomalyId: string): void {
    this.anomaliesService.acceptAnomaly(anomalyId);
  }

  changePage({ pageIndex, previousPageIndex }: PageEvent): void {
    if (pageIndex > (previousPageIndex ?? 0)) {
      this.cursor$.next(this.nextCursor);
    } else {
      this.cursor$.next(this.prevCursor);
    }
  }

  hasChild = (_: number, node: AnomalyFlatNode) => node.expandable;
}
