// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import * as constant from '../src/constants';
import { LogHeader } from './log_header';
import { LogRow } from './log_row';
import { FfxLogData } from '../src/log_data';
import { LogField } from '../src/fields';
import { FilterExpression } from '../src/filter';
import { State } from '../src/state';

export const WRAP_LOG_TEXT_ATTR = 'wrap-log-text';

export class LogList {
  private logList: HTMLDivElement;
  private logHeader: LogHeader;
  private hasPreviousLog: boolean = false;
  private maxWidths: Array<number>;

  constructor(private state: State) {
    this.maxWidths = new Array(Object.keys(state.currentFields).length).fill(0);
    this.logHeader = new LogHeader(state);
    this.logList = this.initLogList();
    this.logWrapping = state.shouldWrapLogs;

    state.addEventListener('filterChange', (e) => {
      const event = e as CustomEvent;
      const filter: FilterExpression = event.detail.filter;
      const logRows = Array.from(this.logList.children).slice(1);

      if (filter.isEmpty()) {
        for (const element of logRows) {
          element.removeAttribute('hidden');
        }
      } else {
        for (const element of logRows) {
          if (filter.accepts(element.children[0])) {
            element.removeAttribute('hidden');
          } else {
            element.setAttribute('hidden', '');
          }
        }
      }
    });
  }

  /**
   * Returns the core element.
   */
  get element() {
    return this.logList;
  }

  /**
   * Appends a log to the current list of logs
   */
  public addLog(log: FfxLogData) {
    this.addLogElement(log);
    this.hasPreviousLog = true;
  }

  /**
   * Resets the state and contents of the webview to contain nothing.
   * The persistent state is maintained as that represents user selections.
   */
  public reset() {
    this.logList.innerHTML = '';
    this.logList.appendChild(this.logHeader.element);
    this.hasPreviousLog = false;
  }

  /**
   * Defines whether or not to wrap the log text.
   *
   * @param logWrapActive if true the log text will be wrapped
   */
  public set logWrapping(logWrapActive: boolean) {
    if (logWrapActive) {
      this.logList.setAttribute(WRAP_LOG_TEXT_ATTR, 'true');
    } else {
      this.logList.removeAttribute(WRAP_LOG_TEXT_ATTR);
    }
  }

  /**
   * Initializes the element that contains the list of logs.
   *
   * @return the log list element.
   */
  private initLogList(): HTMLDivElement {
    let logList = document.createElement('div');
    logList.appendChild(this.logHeader.element);
    logList.id = 'log-list';
    return logList;
  }

  private addLogElement(log: FfxLogData) {
    const logsToDrop = this.logList.children.length - constant.MAX_LOGS;
    for (let i = 0; i < logsToDrop; i++) {
      this.popLogElement();
    }
    this.appendLogElement(log);
    if (!this.logList.parentElement?.matches(':hover')) {
      this.logList.parentElement?.scrollTo(-1, this.logList.scrollHeight);
    };
  }

  private appendLogElement(log: FfxLogData) {
    const element = new LogRow(log, this.hasPreviousLog);
    if (!this.filtersAllow(element)) {
      element.setAttribute('hidden', '');
    }
    this.logList.appendChild(element);
    this.setMaxCellWidth(element);
  }

  private setMaxCellWidth(row: Element) {
    for (const cell in Array.from(row.children)) {
      let id = row.children[cell].id as LogField;
      let width = this.maxWidths[cell];
      if (width < row.children[cell].scrollWidth) {
        this.maxWidths[cell] = row.children[cell].scrollWidth;
        this.logHeader.setMaxCellWidth(id, this.maxWidths[cell]);
      }
    }
  }

  private popLogElement() {
    this.logList.removeChild(this.logList.children[-1]);
  }

  private filtersAllow(el: Element) {
    return this.state.currentFilter.accepts(el);
  }
}
