import { useEffect, useState } from 'react';
import { Box, Divider, FormControlLabel, Link, Switch, Typography } from '@mui/material';

import { DiffCell, isDiff } from '../../common/DiffView';
import { NO_VALUE } from '../constants';
import { useAppDispatch, useAppSelector } from '../store';
import { setListPage, setListPerPage, setListSort } from '../store/activitySlice';
import { selectChangesList, selectFileIntegrityMonitoringList } from '../store/activitySlice/selectors';
import { fetchChanges, fetchChangesWithMessages, fetchFileIntegrityMonitoring } from '../store/activitySlice/thunks';
import type { Change, FileIntegrityMonitoring } from '../store/activitySlice/types';
import { formatTimestamp } from '../utils/format';
import PaginatedSection, { type Column } from './PaginatedSection';

const changesColumns: Column<Change>[] = [
  { label: 'Promise type', sortKey: 'promisetype', render: r => r.promisetype ?? NO_VALUE },
  { label: 'Promiser', sortKey: 'promiser', render: r => r.promiser ?? NO_VALUE },
  {
    label: 'Log messages',
    sortKey: 'logmessages',
    render: r =>
      r.logmessages?.length
        ? r.logmessages.map((m, i) => (
            <Typography key={i} variant="body2">
              {m}
            </Typography>
          ))
        : NO_VALUE
  },
  {
    label: 'Change time',
    sortKey: 'changetime',
    render: r => formatTimestamp(r.changetime, { withSeconds: true, fallback: NO_VALUE })
  }
];

const CHANGE_TYPE_DIFF = 'DIFF';

// Labels of the file integrity monitoring report, see views/partials/fim.php.
const changeTypesMapping: Record<string, string> = {
  C: 'Content change',
  S: 'File stats',
  N: 'File added',
  R: 'File removed',
  [CHANGE_TYPE_DIFF]: CHANGE_TYPE_DIFF
};

const fimColumns: Column<FileIntegrityMonitoring>[] = [
  { label: 'File name', sortKey: 'filename', render: r => r.filename ?? NO_VALUE },
  {
    label: 'Change type',
    sortKey: 'changetype',
    render: r => changeTypesMapping[r.changetype] ?? r.changetype ?? NO_VALUE
  },
  {
    label: 'Change details',
    sortKey: 'changedetails',
    render: r => {
      if (!r.changedetails?.length) {
        return NO_VALUE;
      }
      return r.changetype === CHANGE_TYPE_DIFF || isDiff(r.changedetails) ? (
        <DiffCell details={r.changedetails} title={r.filename} />
      ) : (
        r.changedetails.map((d, i) => (
          <Typography key={i} variant="body2">
            {d}
          </Typography>
        ))
      );
    }
  },
  {
    label: 'Change time',
    sortKey: 'changetimestamp',
    render: r => formatTimestamp(r.changetimestamp, { withSeconds: true, fallback: NO_VALUE })
  }
];

export const ActivityTab = ({ hostkey }: { hostkey: string }) => {
  const dispatch = useAppDispatch();
  const changes = useAppSelector(state => selectChangesList(state, hostkey));
  const fileIntegrityMonitoring = useAppSelector(state => selectFileIntegrityMonitoringList(state, hostkey));
  const [onlyWithMessages, setOnlyWithMessages] = useState(false);
  const handleLogMessagesChange = (event: React.ChangeEvent<HTMLInputElement>) =>
    setOnlyWithMessages(event.target.checked);

  useEffect(() => {
    if (hostkey) {
      dispatch(
        fetchChanges({
          hostkey,
          page: changes.page,
          perPage: changes.perPage,
          sort: changes.sort,
          order: changes.order,
          onlyWithMessages
        })
      );
    }
  }, [dispatch, hostkey, changes.page, changes.perPage, changes.sort, changes.order, onlyWithMessages]);

  useEffect(() => {
    if (hostkey) {
      dispatch(fetchChangesWithMessages({ hostkey }));
    }
  }, [dispatch, hostkey]);

  useEffect(() => {
    if (hostkey) {
      dispatch(
        fetchFileIntegrityMonitoring({
          hostkey,
          page: fileIntegrityMonitoring.page,
          perPage: fileIntegrityMonitoring.perPage,
          sort: fileIntegrityMonitoring.sort,
          order: fileIntegrityMonitoring.order
        })
      );
    }
  }, [
    dispatch,
    hostkey,
    fileIntegrityMonitoring.page,
    fileIntegrityMonitoring.perPage,
    fileIntegrityMonitoring.sort,
    fileIntegrityMonitoring.order
  ]);

  const changesActions = (
    <Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', flexGrow: 1 }}>
      <Link href="/reports/changes">View all changes</Link>
      <FormControlLabel
        labelPlacement="start"
        control={<Switch checked={onlyWithMessages} onChange={handleLogMessagesChange} />}
        label={
          <Typography variant="body2" component="span">
            Log messages only (
            <Box component="span" sx={{ color: 'blue.600' }}>
              {changes.totalWithMessages ?? NO_VALUE} / {changes.totalUnfiltered}
            </Box>
            )
          </Typography>
        }
      />
    </Box>
  );

  return (
    <Box>
      <PaginatedSection
        title="Changes"
        actions={changesActions}
        testId="changes"
        columns={changesColumns}
        list={changes}
        emptyText="No changes reported for this host."
        onChangePage={page => dispatch(setListPage({ hostkey, list: 'changes', page }))}
        onChangePerPage={perPage => dispatch(setListPerPage({ hostkey, list: 'changes', perPage }))}
        onSort={sort => dispatch(setListSort({ hostkey, list: 'changes', sort }))}
      />
      <Divider sx={{ my: 2.5 }} />
      <PaginatedSection
        title="File integrity monitoring"
        actions={<Link href="/reports/file_integrity_monitoring">View all events</Link>}
        testId="fim"
        columns={fimColumns}
        list={fileIntegrityMonitoring}
        emptyText="No file integrity events reported for this host."
        onChangePage={page => dispatch(setListPage({ hostkey, list: 'fileIntegrityMonitoring', page }))}
        onChangePerPage={perPage => dispatch(setListPerPage({ hostkey, list: 'fileIntegrityMonitoring', perPage }))}
        onSort={sort => dispatch(setListSort({ hostkey, list: 'fileIntegrityMonitoring', sort }))}
      />
    </Box>
  );
};
