// 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>;
  public filterResultsCount: number = 0;

  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;
    this.logList.ariaColCount = `${Object.keys(state.currentFields).length}`;

    state.addEventListener('filterChange', (e) => {
      const event = e as CustomEvent;
      const filter: FilterExpression = event.detail.filter;
      const logRows = Array.from(this.logList.children).slice(1);
      this.logList.ariaColCount = `${this.logList.children.length}`;
      let resultCount = 0;

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

      this.filterResultsCount = resultCount;
    });
  }

  /**
   * 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);
    this.hasPreviousLog = false;
    this.filterResultsCount = 0;
  }

  /**
   * 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);
    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);
    element.updateComplete
      .then(() => {
        this.setMaxCellWidth(element.children[0]);
      })
      .catch(e => { });
  }

  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);
  }
}
