import React, { useEffect, useRef, useState } from 'react';
import {
  makeStyles,
  Table,
  TableRow,
  TableHead,
  TableCell,
  TableBody,
  TableContainer,
  Paper,
  IconButton,
  Tooltip,
  Typography,
  Button,
  withStyles,
} from '@material-ui/core';
import { DeleteSweep as ClearLogsIcon } from '@material-ui/icons';

import { logsText } from '../../helpers/static-text';
import { LogLine } from '../../types';
import { useSettings } from '../../hooks';
import FilterInput from '../FilterInput';
import ModNameSelect from './ModNameSelect';
import PageContainer from '../PageContainer';
import { useRecoilState } from 'recoil';
import { logLinesState } from '../../store';
import { debugConsole } from '../../helpers/console-log';

const useStyles = makeStyles(({ palette, spacing }) => ({
  Error: {
    color: palette.error.light,
  },
  Quit: {
    color: palette.error.light,
  },
  Warning: {
    color: palette.warning.light,
  },
  Success: {
    color: palette.success.light,
  },
  Info: {
    color: palette.info.light,
  },
  Fatal: {
    color: palette.error.light,
  },
  Debug: {
    color: palette.text.disabled,
  },
  Message: {},
  wrapper: {
    padding: spacing(3),
  },
  container: {
    flex: 1,
    overflowY: 'auto',
    background: palette.grey[900],
  },
  logRow: {
    border: 0,
  },
  header: {
    backgroundColor: 'white',
  },
  modSelectHeader: {
    width: 150,
  },
  nameHeader: {
    display: 'flex',
    justifyContent: 'space-between',
    alignItems: 'center',
  },
  modNameCell: {
    overflowX: 'hidden',
    textOverflow: 'ellipsis',
    whiteSpace: 'nowrap',
  },
  logCountHeader: {
    width: 1,
  },
}));

const LogCell = withStyles((theme) => ({
  body: {
    borderBottom: `1px solid rgba(255, 255, 255, 0.05)`,
  },
  stickyHeader: {
    paddingTop: theme.spacing(1),
    background: theme.palette.background.paper,
  },
}))(TableCell);

const OwmlLog: React.FunctionComponent = () => {
  const styles = useStyles();
  const [logLines, setLogLines] = useRecoilState(logLinesState);
  const {
    settings: { logLinesLimit },
  } = useSettings();

  const [paginatedLines, setPaginatedLines] = useState<LogLine[]>([]);
  const [selectedModName, setSelectedModName] = useState<string>('');
  const [filter, setFilter] = useState('');
  const [page, setPage] = useState<number>(0);

  const containerRef = useRef<HTMLDivElement>(null);
  const isPreviousPageVisible = useRef(false);
  const isNextPageVisible = page > 0;
  const isPaginated = useRef(false);
  const hasHiddenLines = useRef(false);

  useEffect(() => {
    if (!containerRef.current) {
      return;
    }
    debugConsole.log('useEffect: LogsPage scroll reset');
    containerRef.current.scrollTo(0, containerRef.current.scrollHeight);
  }, [paginatedLines]);

  useEffect(() => {
    debugConsole.log('useEffect: LogsPage filter');
    const lowerCaseFilter = filter.toLowerCase();
    const isFilteringByName = filter !== '';
    const isFilteringByMod = selectedModName !== '';

    let filteredLines: LogLine[] = [];
    if (isFilteringByName || isFilteringByMod) {
      filteredLines = logLines.filter((line) => {
        const isFromSelectedMod =
          !isFilteringByMod || line.modName === selectedModName;
        const isMatchWithFilter =
          !isFilteringByName ||
          line.text.toLowerCase().includes(lowerCaseFilter);
        return isMatchWithFilter && isFromSelectedMod;
      });
    } else {
      filteredLines = logLines;
    }

    let lines: LogLine[] = [];
    if (filteredLines.length <= logLinesLimit) {
      lines = filteredLines;
    }

    const end = filteredLines.length - page * logLinesLimit;
    const start = end > logLinesLimit ? end - logLinesLimit : 0;
    lines = filteredLines.slice(start, end);

    isPreviousPageVisible.current =
      page < Math.floor((filteredLines.length - 1) / logLinesLimit);
    isPaginated.current = filteredLines.length !== lines.length;
    hasHiddenLines.current = logLines.length !== lines.length;

    setPaginatedLines(lines);
  }, [filter, logLines, selectedModName, page, logLinesLimit]);

  useEffect(() => {
    debugConsole.log('useEffect: LogsPage pagination reset');
    setPage(0);
  }, [filter, selectedModName]);

  function handlePreviousPageClick() {
    setPage((prevPage) => prevPage + 1);
  }

  function handleNextPageClick() {
    setPage((prevPage) => prevPage - 1);
  }

  function handleClearClick() {
    setLogLines([]);
  }

  return (
    <PageContainer maxWidth={false}>
      <TableContainer
        component={Paper}
        className={styles.container}
        ref={containerRef}
      >
        <Table size="small" stickyHeader>
          <TableHead>
            <TableRow>
              <LogCell className={styles.nameHeader}>
                <FilterInput
                  onChange={setFilter}
                  value={filter}
                  label={logsText.filterLogsLabel}
                />
                {logLines.length > 1 && (
                  <Typography variant="subtitle2" color="textSecondary">
                    {hasHiddenLines.current &&
                      logsText.showingLines(paginatedLines.length)}
                    {logsText.entries(logLines.length)}
                    {isPaginated.current && logsText.page(page + 1)}
                  </Typography>
                )}
                <Tooltip title={logsText.clearLogs}>
                  <IconButton size="small" onClick={handleClearClick}>
                    <ClearLogsIcon />
                  </IconButton>
                </Tooltip>
              </LogCell>
              <LogCell className={styles.modSelectHeader}>
                <ModNameSelect
                  value={selectedModName}
                  onChange={setSelectedModName}
                  logLines={logLines}
                />
              </LogCell>
              <LogCell className={styles.logCountHeader}>#</LogCell>
            </TableRow>
          </TableHead>
          <TableBody>
            {isPreviousPageVisible.current && (
              <TableRow>
                <LogCell colSpan={3}>
                  <Button
                    onClick={handlePreviousPageClick}
                    fullWidth
                    variant="outlined"
                  >
                    {logsText.showPrevious(logLinesLimit)}
                  </Button>
                </LogCell>
              </TableRow>
            )}
            {paginatedLines.map((line: LogLine) => (
              <React.Fragment key={line.id}>
                <TableRow>
                  <LogCell className={styles[line.type]}>
                    {line.text.split('\n').map((text) => (
                      <div>{text}</div>
                    ))}
                  </LogCell>
                  <LogCell className={styles.modNameCell}>
                    {line.modName}
                  </LogCell>
                  <LogCell>{line.count > 1 ? line.count : ''}</LogCell>
                </TableRow>
              </React.Fragment>
            ))}
            {isNextPageVisible && (
              <TableRow>
                <LogCell colSpan={3}>
                  <Button
                    onClick={handleNextPageClick}
                    fullWidth
                    variant="outlined"
                  >
                    {logsText.showNext(logLinesLimit)}
                  </Button>
                </LogCell>
              </TableRow>
            )}
          </TableBody>
        </Table>
      </TableContainer>
    </PageContainer>
  );
};

export default OwmlLog;