import { IObjectController } from './interfaces/object-controller';
import { ChangeDetectorRef, Directive, ElementRef, Input, NgZone, OnDestroy, OnInit } from '@angular/core';
import { IBaseFleioObjectModel } from '@fleio-api/base-model/base-fleio-object.model';
import { DEFAULT_BOOST_INTERVALS, RefreshTimer } from '../../ui-api/helpers/refresh-timer';
import { Subscription } from 'rxjs';
import { environment } from '@environments/environment';
import { IAction } from '@objects-view/interfaces/actions/action';
import { ConfigService } from '@shared/config/config.service';
import {IDetailsTab} from '@objects-view/interfaces/details/details-tab';
import {AuthService} from '@shared/auth/auth.service';

@Directive()
export class DetailsComponentBase<ObjectType extends IBaseFleioObjectModel>
  implements OnInit, OnDestroy {
  @Input() objectController: IObjectController;
  @Input() componentTabIndex: number;
  @Input() data?: Record<string, any>;
  @Input() detailsActions?: Array<IAction>;
  public primaryAction: IAction = null;

  protected ignoreObjectController = false;
  protected tabActive = false;
  protected refreshTimer: RefreshTimer;
  private refreshTimerInitialized = false;
  private tabEventsInitialized = false;
  public authSvc: AuthService;
  public elementRef: ElementRef;
  public changeDetector: ChangeDetectorRef;

  private currentTabIndexSubscription: Subscription;

  constructor(
    private ngZone?: NgZone,
    protected changeDetectorRef?: ChangeDetectorRef,
    private receivedConfigService?: ConfigService
  ) {
  }

  ngOnInit(refreshTimerInterval?: number) {
    if (this.refreshData.toString().length > 21) {
      // if function code length is larger than 21, it means it is used, so we can init refresh timer
      if (!refreshTimerInterval) {
        if (this.receivedConfigService) {
          this.setupRefreshTimer(this.receivedConfigService.getDefaultRefreshInterval());
        } else {
          console.error('Cannot init refresh timer as config service is undefined!');
        }
      } else {
        this.setupRefreshTimer(refreshTimerInterval);
      }
    }
    this.initTabEvents();
    this.primaryAction = this.getPrimaryAction();
  }

  stopRefreshTimer() {
    if (this.refreshTimer) {
      this.refreshTimer.stop();
      delete this.refreshTimer;
    }
  }

  ngOnDestroy(): void {
    this.stopRefreshTimer();

    if (this.currentTabIndexSubscription) {
      this.currentTabIndexSubscription.unsubscribe();
      this.currentTabIndexSubscription = null;
    }
  }

  public get object(): ObjectType {
    if (this.objectController) {
      if (!this.data?.isPluginTab) {
        return this.objectController.object as ObjectType;
      } else {
        return this.objectController.object['resources'].service_resources as ObjectType;
      }
    } else {
      if (environment.enableErrorLogging) {
        console.error(`objectController was not set for ${this.constructor.name}`);
      }
    }
  }

  public getPrimaryAction() {
    let firstAction = null;
    if (this.detailsActions && Array.isArray(this.detailsActions)) {
      firstAction = this.detailsActions[0];
      for (const action of this.detailsActions) {
        if (action.primary) {
          return action;
        }
      }
    }
    return firstAction;
  }

  filterTabs(tabs: IDetailsTab[]): IDetailsTab[] {
    return tabs.filter(tab => {
      if (tab.featureName) {
        return this.authSvc.feature(tab.featureName);
      } else {
        return true;
      }
    });
  }

  switchTab(newIndex) {
    this.objectController.currentTabIndex.next(newIndex);
  }

  protected initTabEvents() {
    if (this.tabEventsInitialized === true) {
      console.error('Tab events are already initialized!');
      return;
    }
    if (!this.objectController) {
      if (environment.enableErrorLogging && !this.ignoreObjectController) {
        console.error('Cannot subscribe to tab changing events because no objectController was found!');
      }
      return;
    }
    this.currentTabIndexSubscription = this.objectController.currentTabIndex$.subscribe(tabIndex => {
      if (tabIndex === this.componentTabIndex) {
        if (!this.tabActive) {
          this.tabActive = true;
          this.tabActivated();
        }
      } else {
        if (this.tabActive) {
          this.tabActive = false;
          this.tabDeactivated();
        }
      }
      const tabs = this.filterTabs(this.objectController.getDetailsCardData().tabs);
      let tab = null;
      if (tabs && tabs.length > 1) {
        tab = tabs[tabIndex];
      }
      if (tab) {
        const tabIdentifier: string = tab.tabIdentifier.toLowerCase();
        if (tabIndex === 0 && window.history && window.history.replaceState) {
          let queryParams = '';
          if (window.location.href.includes('?')) {
            queryParams = window.location.href.split('?')[1];
            queryParams = queryParams.replace(window.location.hash, '');
          }
          let url: string;
          if (queryParams) {
            url = `${window.location.pathname}?${queryParams}#${tabIdentifier}`;
          } else {
            url = `${window.location.pathname}#${tabIdentifier}`;
          }
          let currentHash = window.location.hash;
          let currentHashIsAnchor = false;
          if (currentHash) {
            currentHash = currentHash.replace('#', '');
            currentHashIsAnchor = /^\d+$/.test(currentHash);
          }
          if (!currentHashIsAnchor) {
            window.history.replaceState(null, null, url);
          }
        } else {
          window.location.hash = tabIdentifier;
        }
      }
      this.tabEventsInitialized = true;
    });
  }

  protected setupRefreshTimer(interval: number) {
    if (this.refreshTimerInitialized) {
      console.warn('Refresh timer was already initialized!');
      return;
    }
    this.refreshTimer = new RefreshTimer(interval, () => {
      this.refreshData();
    }, this.receivedConfigService, this.ngZone, this.changeDetectorRef, this.tabActive);
    this.refreshTimerInitialized = true;
  }

  protected boostRefreshTimer(boostIntervals: number[] = DEFAULT_BOOST_INTERVALS) {
    if (!this.refreshTimer) {
      console.error('refresh timer is not initialized');
      return;
    }

    this.refreshTimer.boost(boostIntervals);
  }

  protected initTabData() {
    // method used for initializing different data, e.g. changing actionCallback when changing tabs
  }

  protected tabActivated() {
    this.initTabData();
    if (this.refreshTimer) {
      this.refreshData();
      this.refreshTimer.start();
    }
  }

  protected tabDeactivated() {
    if (this.refreshTimer) {
      this.refreshTimer.stop();
    }
  }

  protected refreshData() {
  }

  dataChanged() {
  }
}
