import { Component, Input, OnInit } from '@angular/core';
import { DbModel } from 'src/app/model/entities/db-model';
import { SpinnerService } from 'src/app/service/spinner.service';
import { User } from 'src/app/model/auth/user';
import { ActivatedRoute, Router } from '@angular/router';
import { TableColumn } from 'src/app/modules/shared/components/table/table.model';
import { Observable } from 'rxjs';

interface History {
  id?: number;
  editor?: User;
  deleted?: boolean;
  created?: Date;
  updated?: Date;

  [x: string | number | symbol]: unknown;
}

@Component({
  selector: 'app-history-sidebar',
  templateUrl: './history-sidebar.component.html',
  styleUrl: './history-sidebar.component.scss',
})
export class HistorySidebarComponent<T> implements OnInit {
  @Input({ required: true }) loadHistory!: (
    id: number
  ) => Observable<DbModel[]>;
  @Input({ required: true }) columns!: TableColumn<T>[];
  historyId!: number;

  private translations: { [key: string]: string } = {};
  public history: History[] = [];
  public showSidebar: boolean = false;

  constructor(
    private spinner: SpinnerService,
    private route: ActivatedRoute,
    private router: Router
  ) {
    this.spinner.show();
    const id = this.route.snapshot.params['historyId'];
    if (!id) {
      throw new Error('History ID is required');
    }
    this.historyId = +id;
  }

  ngOnInit() {
    this.open();
  }

  open(): void {
    this.columns.forEach(column => {
      this.translations[column.name] = column.translationKey;
    });

    this.showSidebar = true;
    this.loadHistory(this.historyId).subscribe(data => {
      this.history = data ? this.processHistory(data) : [];
      this.spinner.hide();
    });

    let oldHistory: Partial<History> = {};
    for (const history of this.history) {
      const attributes = Object.keys(history).map(key => {
        return key;
      });
      for (const attribute of attributes) {
        if (history[attribute] === oldHistory[attribute]) {
          delete oldHistory[attribute];
        }
      }

      oldHistory = history;
    }
  }

  close() {
    const backRoute = this.historyId ? '../..' : '..';

    this.router.navigate([backRoute], { relativeTo: this.route }).then(() => {
      this.spinner.hide();
    });
  }

  private processHistory(data: DbModel[]): History[] {
    const history = (data as History[]).map(entry => {
      const filteredEntry: History = {};
      for (const key in entry) {
        if (!key.startsWith('_') && !key.startsWith('__')) {
          filteredEntry[key] = this.flattenValue(entry[key]);
        }
      }
      return filteredEntry;
    });

    const reversedHistory = [...history].reverse();

    let cumulativeHistory: Partial<History> = {};
    for (const entry of reversedHistory) {
      const attributes = Object.keys(entry);
      for (const attribute of attributes) {
        if (
          attribute !== 'editor' &&
          entry[attribute] === cumulativeHistory[attribute]
        ) {
          delete entry[attribute];
        }
      }
      cumulativeHistory = { ...cumulativeHistory, ...entry };
    }

    return reversedHistory.reverse();
  }

  private flattenValue(value: unknown): string {
    if (value === null) {
      return '';
    }

    if (value && typeof value === 'object') {
      return (
        Array.isArray(value)
          ? value
          : Object.entries(value)
              .filter(([key]) => !key.startsWith('_') && !key.startsWith('__'))
              .map(([, val]) => val)
      )
        .map(item => this.flattenValue(item))
        .join(', ');
    }
    return String(value);
  }

  public getAttributeTranslationKey(key: string): string {
    return this.translations[key] || `history.${key}`;
  }
}
