import { BehaviorSubject, Subject } from 'rxjs';
import {
  IDeleteLabelsEvent,
  IHoverInLabelsEvent,
  IInitOptions,
  ILabel,
  ILabelingEvent,
  ILabelStyle,
  IPagination,
  ISafeAny,
  ISearchLabelByIndexParams,
  ISearchLabelByUuidParams,
  ISearchResult,
  ISearchTableCellParams,
  ISerarchParams,
  IViewPort,
  LabelTableMode,
  LabelTextMode,
  PdfMode
} from './label.type';
import { Log, Safe } from './label.util';

interface IOptions {
  dev?: boolean;
  logUnhandledEvents?: boolean;
  logAllEvents?: boolean;
  logIgnoreEvents?: string[];
}

export class LabelHub {
  id: string;
  protected _hoverInLabelsEvent: IHoverInLabelsEvent | null = null;
  protected _labelingEvent: ILabelingEvent | null = null;
  protected _dev = false;
  protected _logUnhandledEvents = false;
  protected _logAllEvents = false;
  protected _logIgnoreEvents: string[] = [];
  protected _api: ISafeAny;
  protected _ready = false;
  protected _loaded = false;
  protected _zoom = 1;
  protected _pagination: IPagination = {
    pageCount: 1,
    pageNumber: 1
  };
  /**
   * 标注器是否加载完成
   */
  readonly loaded$ = new BehaviorSubject(this._loaded);
  /**
   * 标注器是否准备完毕
   */
  readonly ready$ = new BehaviorSubject(this._ready);
  /**
   * 初始化数据流
   */
  readonly init$ = new BehaviorSubject<IInitOptions | null>(null);
  /**
   * 搜索结果
   */
  readonly searchResult$ = new BehaviorSubject<ISearchResult>({
    keyword: '',
    caseSensitive: false,
    result: []
  });
  /**
   * Tooltip 信息
   */
  readonly hoverInLabelsEvent$: Subject<IHoverInLabelsEvent | null> = new Subject();
  /**
   * 分页信息
   * 默认
   * {
   *   page: 1,
   *   total: 1
   * }
   */
  readonly pagination$ = new BehaviorSubject<IPagination>(this._pagination);
  /**
   * 缩放
   */
  readonly zoom$ = new BehaviorSubject(this._zoom);
  /**
   * 标注列表
   */
  readonly labels$ = new BehaviorSubject<ILabel[] | null>(null);
  /**
   * 表格列表
   */
  readonly tables$ = new BehaviorSubject<ISafeAny | null>(null);
  /**
   *  删除标注
   */
  readonly deleteLabelsEvent$: Subject<IDeleteLabelsEvent | null> = new Subject();
  /**
   *  当前正在标注的标注
   */
  readonly labelingEvent$: Subject<ILabelingEvent | null> = new Subject();
  /**
   * 尺寸变化
   */
  readonly resize$ = new Subject<void>();
  /**
   *  日志流
   */
  readonly log$ = new Subject();

  constructor(
    options?: IOptions
  ) {
    this._dev = options?.dev || false;
    this._logUnhandledEvents = options?.logUnhandledEvents || false;
    this._logAllEvents = options?.logAllEvents || false;
    this._logIgnoreEvents = options?.logIgnoreEvents || [];
  }

  get ready() {
    return this._ready;
  }

  get dev() {
    return this._dev;
  }

  get api() {
    return this._api;
  }

  get loaded() {
    return this._loaded;
  }

  get logUnhandledEvents() {
    return this._logUnhandledEvents;
  }

  get logAllEvents() {
    return this._logAllEvents;
  }

  get logIgnoreEvents() {
    return this._logIgnoreEvents;
  }

  get hoverInLabelsEvent(): ILabelingEvent | null {
    return this._hoverInLabelsEvent;
  }

  get labelingEvent(): ILabelingEvent | null {
    return this._labelingEvent;
  }

  get labeling(): boolean {
    return !!this._labelingEvent;
  }

  /**
   * 设置标注器是否准备完毕
   * @description 最好不要在外部调用，这可能会产生不可预期的效果
   */
  @Log()
  setReady(ready: boolean) {
    this._ready = ready;
    this.ready$.next(this._ready);
  }

  /**
   * 设置标注器是否加载完成
   * @description 最好不要在外部调用，这可能会产生不可预期的效果
   */
  @Log()
  setLoaded(loaded: boolean) {
    this._loaded = loaded;
    this.loaded$.next(this._loaded);
  }

  /**
   * 初始化标注器
   * @description 最好不要在外部调用，这可能会产生不可预期的效果
   */
  @Log()
  init(options: IInitOptions) {
    this.id = options.id;
    // if ([LabelTextMode.textSlip, LabelTextMode.textFrame].includes(options.labelMode as LabelTextMode)) {
    if (options.labelMode in LabelTextMode) { 
      if (options.labels) {
        this.setLabels(options.labels);
      }
    } else {
      if (options.tables) {
        this.setTables(options.tables);
      }
    }
    this.init$.next(options);
  }

  /**
   * 设置标注
   */
  @Log()
  setLabels(labels: ILabel[]) {
    this.labels$.next(labels);
  }

  /**
   * 设置表格
   */
  @Log()
  setTables(tables: ISafeAny) {
    this.tables$.next(tables);
  }

  /**
   * 获取表格标注数据
   */
  @Log()
  @Safe()
  getTableMatrix() {
    return this._api.getTableMatrix();
  }

  /**
   * 设置 Tooltip
   * @description 最好不要在外部调用，这可能会产生不可预期的效果
   */
  @Log()
  hoverInLabels(event: IHoverInLabelsEvent | null) {
    this._hoverInLabelsEvent = event;
    this.hoverInLabelsEvent$.next(event);
  }

  /**
   * 设置分页
   */
  @Log()
  setPagination(pagination: Partial<IPagination>) {
    const p = {
      ...this._pagination,
      ...pagination
    };
    if (p.pageCount < p.pageNumber || p.pageNumber < 1) return;
    this.pagination$.next(p);
    if (this._pagination.pageNumber !== pagination.pageNumber) {
      this._api.setPage(pagination.pageNumber);
    }
    this._pagination = p;
  }

  /**
   * 获取分页信息
   */
  @Log()
  getPagination(): IPagination {
    return this._pagination;
  }


  /**
   * 设置分页(内部调用)
   * @description 同外部调用区别是，它不需要通知标注器更新，最好不要在外部调用，这可能会产生不可预期的效果
   */
  @Log()
  innerSetPagination(pagination: Partial<IPagination>) {
    this._pagination = {
      ...this._pagination,
      ...pagination
    };
    this.pagination$.next(this._pagination);
  }

  /**
   * 设置缩放
   */
  @Log()
  @Safe()
  setZoom(zoom: number) {
    if (this._zoom !== zoom) {
      this._zoom = zoom;
      this.zoom$.next(zoom);
      this._api.setZoom(zoom);
    }
  }

  /**
   * 获取缩放
   */
  @Log()
  getZoom(): number {
    return this._zoom;
  }

  /**
   * 设置标注模式
   */
  @Log()
  @Safe()
  setLabelMode(mode: LabelTextMode | LabelTableMode): void {
    this._api.setLabelMode(mode);
  }

  /**
   * 设置PDF模式
   */
  @Log()
  @Safe()
  setPdfMode(mode: PdfMode): void {
    this._api.setPdfMode(mode);
  }

  /**
   * 打印日志
   */
  @Log()
  setLog(log: { level: string; content: string }) {
    const { level, content } = log;
    // tslint:disable-next-line: no-any
    const logger = (console as any)[level];
    if (logger) {
      logger(content);
    } else {
      console.error('[@bixi/label] 没有找到对应的日志等级', level, content);
    }
    this.log$.next({
      level,
      content
    });
  }

  /**
   * 开始标注
   * @description 最好不要在外部调用，这可能会产生不可预期的效果
   */
  @Log()
  startLabeling(labeling: ILabelingEvent) {
    this._labelingEvent = labeling;
    this.labelingEvent$.next(labeling);
  }

  /**
   * 清除当前标注
   */
  @Log()
  stopLabeling() {
    if (!this._labelingEvent) return;
    this._labelingEvent = null;
    this.labelingEvent$.next(null);
  }

  /**
   * 删除标注
   * @description 最好不要在外部调用，这可能会产生不可预期的效果
   */
  @Log()
  deleteLabels(event: IDeleteLabelsEvent | null) {
    this.deleteLabelsEvent$.next(event);
  }

  /**
   * 搜索
   */
  @Log()
  @Safe()
  search(params: ISerarchParams) {
    this._api.search(params);
  }

  /**
   * 设置搜索结果
   */
  @Log()
  setSearchResult(result: ISearchResult) {
    this.searchResult$.next(result);
  }

  /**
   * 强制标注器重新渲染
   */
  @Log()
  @Safe()
  restore() {
    this._api.restore();
  }

  /**
   * 跳转到某个标签
   */
  @Log()
  @Safe()
  scrollToLabelByUuid(params: ISearchLabelByUuidParams) {
    this._api.scrollToLabel(params);
  }

  /**
   * 通过索引跳转到某个标签
   */
  @Log()
  @Safe()
  scrollToLabelByIndex(params: ISearchLabelByIndexParams) {
    this._api.scrollToLabelByIdx(params);
  }


  /**
   * 通过坐标跳转到表格单元格
   */
  @Log()
  @Safe()
  scrollToTableCell(params: ISearchTableCellParams) {
    this._api.scrollToTableCell(params);
  }

  /**
   * 获取页面的显示相关信息
   */
  @Log()
  @Safe()
  getViewport(): IViewPort[] {
    return this._api.getViewport();
  }

  /**
   * 获取所有被选中的 Labels
   */
  @Log()
  @Safe()
  getSelectedLabels(): ILabel[] {
    return this._api.getSelectedLabels();
  }

  setApi(api: ISafeAny) {
    this._api = api;
  }

  /**
   * 重置已渲染标注填充色和边框
   */
  @Log()
  @Safe()
  resetLabelsStyle(params: ILabelStyle[]): void {
    this._api.resetLabelsStyle(params);
  }

  /**
   * 重置选中的标注
   */
  @Log()
  @Safe()
  resetSelectedLabels(params: Required<ILabelStyle>[]): void {
    this._api.resetSelectedLabels(params);
  }
  
  /**
   * 获取文档文本内容
   */
  @Log()
  @Safe()
  getDocContent(): string {
    return this._api.getDocContent();
  }

  /**
   * enable merge|split cross page tables
   */
  @Log()
  @Safe()
  enableMergeOrSplitTables(enable = false): void {
    this._api.enableMergeOrSplitTables(enable);
  }

  /**
   * 销毁 Hub
   * @description 最好不要在外部调用，这可能会产生不可预期的效果
   */
  @Log()
  destory() {
    this.loaded$.complete();
    this.ready$.complete();
    this.init$.complete();
    this.searchResult$.complete();
    this.hoverInLabelsEvent$.complete();
    this.pagination$.complete();
    this.zoom$.complete();
    this.labels$.complete();
    this.tables$.complete();
    this.deleteLabelsEvent$.complete();
    this.labelingEvent$.complete();
    this.log$.complete();
  }
}
