import { Component, EventEmitter, HostListener, Input, OnDestroy, OnInit, Output, ViewChild } from '@angular/core';
import { IObjectListController } from '../interfaces/object-list-controller';
import { ITableData } from '../interfaces/table-data/table-data';
import { MatTableDataSource } from '@angular/material/table';
import { MatSort, Sort } from '@angular/material/sort';
import { IOrdering } from '@shared/ui-api/interfaces/route-config/ordering';
import { OrderingService } from '@shared/ui-api/ordering.service';
import { OrderingHelper } from '@shared/ui-api/helpers/ordering-helper';
import { ITableRow } from '../interfaces/table-data/table-row';
import { ColumnType, IColumnDefinition } from '../interfaces/table-data/column-definition';
import { LineDirection } from '../status-line/status-line.component';
import { Subscription } from 'rxjs';
import { state, style, trigger } from '@angular/animations';
import { FleioId } from '@fleio-api/base-model/base-fleio-object.model';
import { AppColor } from '../../common/enums/app-color.enum';
import { ThemingService } from '@shared/ui/theming/theming.service';
import { AppLocalStorageService } from '@shared/ui-api/app-local-storage.service';
import { IObjectController } from '@objects-view/interfaces/object-controller';
import { ComponentHostDirective } from '@objects-view/object-details/component-host.directive';

@Component({
  selector: 'app-list-view',
  templateUrl: './list-view.component.html',
  styleUrls: ['./list-view.component.scss'],
  animations: [
    trigger('detailExpand', [
      state('collapsed', style({height: '0', minHeight: '0', overflow: 'hidden'})),
      state('expanded', style({height: '*', overflow: 'visible'})),
      // transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')),
    ]),
  ],
})
export class ListViewComponent implements OnInit, OnDestroy {
  @Input() objectsListController: IObjectListController;
  @Input() insideCard = false;
  @Input() replaceSort = false;
  @Input() activeSort: Sort = null;
  @Output() changeSort = new EventEmitter<Sort>();
  @ViewChild(MatSort) matSort: MatSort;
  @ViewChild(ComponentHostDirective) expandedRow: ComponentHostDirective;
  expandedRows = null;

  public tableData: ITableData;
  public visibleActions;
  public tableDataSource: MatTableDataSource<ITableRow>;
  private orderOptions: IOrdering[];
  private tableDataSubscription: Subscription;
  private orderingSubscription: Subscription;

  public ColumnType = ColumnType;
  public LineDirection = LineDirection;
  public expandedObjectId: FleioId | null = null;
  public LineColor = AppColor;
  noItemsTxt = $localize`No items`;
  private appTopOffsetSubscription: Subscription;
  noObjectsBaseTopOffset = this.insideCard ? 0 : 200;
  noObjectsTopOffset = this.insideCard ? '0' : '200px';
  expandedRowController: IObjectController;

  constructor(
    private themingService: ThemingService,
    private orderingService: OrderingService,
    private appLocalStorageService: AppLocalStorageService,
  ) {
  }

  setVisibleActions() {
    if (window.innerWidth < 720) {
      this.visibleActions = 0;
    } else {
      this.visibleActions = this.tableData.header.visibleActions;
    }
  }

  @HostListener('window:resize', ['$event'])
  onResize(event) {
    this.setVisibleActions();
  }

  ngOnInit() {
    if (!this.replaceSort) {
      this.orderingSubscription = this.orderingService.ordering$.subscribe(ordering => {
        if (ordering) {
          this.activeSort = OrderingHelper.toSort(ordering.default);
          this.orderOptions = ordering.options;
        } else {
          this.activeSort = {active: null, direction: null};
          this.orderOptions = [];
        }
      });
    }
    if (this.objectsListController) {
      this.tableDataSubscription = this.objectsListController.tableData$.subscribe(tableData => {
        if (tableData) {
          // add status column
          if (tableData.header.showStatus && !tableData.header.columnNames.includes('(status)')) {
            tableData.header.columns.unshift({
              type: ColumnType.Status,
              displayName: null,
              fieldName: '(status)',
              enableSort: false,
              flex: 'none',
            });
            tableData.header.columnNames.unshift('(status)');
          }

          // adjust visible actions count
          if (typeof tableData.header.visibleActions !== 'number') {
            tableData.header.visibleActions = 4;
          }

          // adjust flex and hide settings
          for (const column of tableData.header.columns) {
            column.flex = column.flex || undefined;
            column.flexXs = column.flexXs || column.flex;
            column.flexGtMd = column.flexGtMd || column.flex;
            if (column.hide) {
              if (typeof column.hide === 'string') {
                const key = column.hide as string;
                column.hide = {};
                column.hide[key] = true;
              }
            } else {
              column.hide = {};
            }
          }

          this.tableDataSource = new MatTableDataSource(tableData.rows);
          this.tableData = tableData;
          this.setVisibleActions();
          if (this.expandedObjectId) {
            // send changed data to expanded object
            const expandedTableRow = this.tableData.rows.find(r => r.object.id === this.expandedObjectId);
            if (expandedTableRow) {
              const expandedRow = expandedTableRow.object;
              this.expandedRowController = this.objectsListController.controller(expandedRow);
              this.expandedRow.dataChanged();
            } else {
              this.expandedObjectId = null;
            }
          }
        } else {
          this.tableData = null;
        }
      });
    } else {
      console.error('Cannot receive table data due to missing objectsListController');
    }

    if (!this.insideCard) {
      this.appTopOffsetSubscription = this.themingService.observableAppTopOffset.subscribe(value => {
        const newOffset = this.noObjectsBaseTopOffset + value;
        this.noObjectsTopOffset = `${newOffset}px`;
      });
    }

    if (this.tableData?.defaultExpandedRows) {
      this.expandedRows = this.tableData.defaultExpandedRows;
    }
  }

  sort(sortData: Sort) {
    if (this.replaceSort) {
      this.changeSort.emit(sortData);
      this.activeSort = sortData;
    } else {
      this.orderingService.orderBy(OrderingHelper.fromSort(sortData), true);
    }
  }

  ngOnDestroy(): void {
    if (this.tableDataSubscription) {
      this.tableDataSubscription.unsubscribe();
      this.tableDataSubscription = null;
    }
    if (this.orderingSubscription) {
      this.orderingSubscription.unsubscribe();
      this.orderingSubscription = null;
    }
    if (this.appTopOffsetSubscription) {
      this.appTopOffsetSubscription.unsubscribe();
      this.appTopOffsetSubscription = null;
    }
  }

  toggleRowDetails(row: ITableRow, column: IColumnDefinition) {
    if (column.type !== ColumnType.Actions) {
      if (this.tableData.expandableRows && row.expandable) {
        if (this.expandedObjectId === row.object.id) {
          this.expandedObjectId = null;
        } else {
          this.expandedObjectId = row.object.id;
          this.expandedRowController = this.objectsListController.controller(row.object);
        }
      }
    }
  }

  expandMoreRows(row: ITableRow) {
    if (row.showsRows) {
      const identifier = row.showsRows;
      if (!this.expandedRows) {
        this.expandedRows = {};
      }
      if (!this.expandedRows.hasOwnProperty(identifier)) {
        this.expandedRows[identifier] = true;
      } else {
        this.expandedRows[identifier] = !this.expandedRows[identifier];
      }
      this.appLocalStorageService.setTicketListExpandedRows(this.expandedRows);
    }
  }
}
