import React, { useState } from "react";
import { Form, Col } from 'react-bootstrap';
import * as GQL from "src/core/generated-graphql";
import { StashService } from "src/core/StashService";

function convertTime(logEntry: GQL.LogEntryDataFragment) {
  function pad(val : number) {
    var ret = val.toString();
    if (val <= 9) {
      ret = "0" + ret;
    }

    return ret;
  }

  var date = new Date(logEntry.time);
  var month = date.getMonth() + 1;
  var day = date.getDate();
  var dateStr = date.getFullYear() + "-" + pad(month) + "-" + pad(day);
  dateStr += " " + pad(date.getHours()) + ":" + pad(date.getMinutes()) + ":" + pad(date.getSeconds());

  return dateStr;
}

function levelClass(level : string) {
  return level.toLowerCase().trim();
}

interface ILogElementProps {
  logEntry : LogEntry
}

const LogElement: React.FC<ILogElementProps> = ({ logEntry }) =>  {
  // pad to maximum length of level enum
  var level = logEntry.level.padEnd(GQL.LogLevel.Progress.length);

  return (
    <>
      <span>{logEntry.time}</span>&nbsp;
      <span className={levelClass(logEntry.level)}>{level}</span>&nbsp;
      <span>{logEntry.message}</span>
      <br/>
    </>
  );
}


class LogEntry {
  public time: string;
  public level: string;
  public message: string;
  public id: string;

  private static nextId: number = 0;

  public constructor(logEntry: GQL.LogEntryDataFragment) {
    this.time = convertTime(logEntry);
    this.level = logEntry.level;
    this.message = logEntry.message;

    var id = LogEntry.nextId++;
    this.id = id.toString();
  }
}

// maximum number of log entries to display. Subsequent entries will truncate
// the list, dropping off the oldest entries first.
const MAX_LOG_ENTRIES = 200;
const logLevels = ["Debug", "Info", "Warning", "Error"];

export const SettingsLogsPanel: React.FC = () => {
  const { data, error } = StashService.useLoggingSubscribe();
  const { data: existingData } = StashService.useLogs();
  const [logLevel, setLogLevel] = useState<string>("Info");

  const oldData = (existingData?.logs ?? []).map(e => new LogEntry(e));
  const newData = (data?.loggingSubscribe ?? []).map(e => new LogEntry(e));

  const filteredLogEntries = [...newData.reverse(), ...oldData]
    .filter(filterByLogLevel).slice(0, MAX_LOG_ENTRIES);

  const maybeRenderError = error
    ? <div className={"error"}>Error connecting to log server: {error.message}</div>
    : '';

  function filterByLogLevel(logEntry : LogEntry) {
    if (logLevel === "Debug")
      return true;

    var logLevelIndex = logLevels.indexOf(logLevel);
    var levelIndex = logLevels.indexOf(logEntry.level);

    return levelIndex >= logLevelIndex;
  }

  return (
    <>
      <h4>Logs</h4>
      <Form.Row id="log-level">
        <Col xs={1}>
          <Form.Label>Log Level</Form.Label>
        </Col>
        <Col xs={2}>
          <Form.Control
            as="select"
            defaultValue={logLevel}
            onChange={(event) => setLogLevel(event.currentTarget.value)}
          >
              { logLevels.map(level => (<option key={level} value={level}>{level}</option>)) }
          </Form.Control>
        </Col>
      </Form.Row>
      <div className="logs">
        {maybeRenderError}
        {filteredLogEntries.map((logEntry) =>
          <LogElement logEntry={logEntry} key={logEntry.id}/>
        )}
      </div>
    </>
  );
};
