import { useEffect, useRef } from 'react';
import pluralize from 'pluralize';
import { Box, CircularProgress, Divider, Link, Tooltip, Typography } from '@mui/material';
import AutorenewIcon from '@mui/icons-material/Autorenew';
import InfoIcon from '@mui/icons-material/Info';

import { NO_VALUE } from '../constants';
import { useAppDispatch, useAppSelector } from '../store';
import {
  selectContainersList,
  selectContainersSummary,
  selectContainersSummaryLoading,
  selectImagesList
} from '../store/containersSlice/selectors';
import {
  fetchContainerImages,
  fetchContainers,
  fetchContainersSummary
} from '../store/containersSlice/thunks';
import { setListPage, setListPerPage, setListSort } from '../store/containersSlice';
import type { Container, ContainerImage } from '../store/containersSlice/types';
import { formatBytes, formatContainerStatus, formatPorts, formatRelativeTime } from '../utils/format';
import { capitalize } from '../utils/strings';
import PaginatedSection, { type Column } from './PaginatedSection';

interface ContainersTabProps {
  hostkey: string;
}

const containerColumns: Column<Container>[] = [
  { label: 'Names', sortKey: 'name', render: r => (r.name ? r.name.replace(/^\//, '') : NO_VALUE) },
  { label: 'Image', sortKey: 'image', render: r => r.image ?? NO_VALUE },
  // Command and Ports aren't sortable
  { label: 'Command', render: r => r.command ?? NO_VALUE },
  { label: 'Created', sortKey: 'created_at', render: r => formatRelativeTime(r.created_at) },
  { label: 'Status', sortKey: 'state', render: formatContainerStatus },
  { label: 'Ports', render: r => formatPorts(r.ports) || NO_VALUE },
  { label: 'Engine', sortKey: 'engine', render: r => r.engine ?? NO_VALUE },
  { label: 'Container ID', sortKey: 'id', render: r => (r.id ? r.id.slice(0, 12) : NO_VALUE) }
];

const imageColumns: Column<ContainerImage>[] = [
  { label: 'Repository', sortKey: 'repository', render: r => r.repository ?? NO_VALUE },
  { label: 'Tag', sortKey: 'tag', render: r => r.tag ?? NO_VALUE },
  {
    label: 'Image ID',
    sortKey: 'id',
    render: r => (r.id ? r.id.replace(/^sha256:/, '').slice(0, 12) : NO_VALUE)
  },
  { label: 'Created', sortKey: 'created_at', render: r => formatRelativeTime(r.created_at) },
  { label: 'Size', sortKey: 'size_bytes', render: r => formatBytes(r.size_bytes) },
  { label: 'Engine', sortKey: 'engine', render: r => r.engine ?? NO_VALUE }
];

const SummaryLine = ({ count, children }: { count: number; children: React.ReactNode }) => (
  <Box>
    <Typography component="span" sx={{ color: 'text.primary', fontWeight: 500 }}>
      {count}
    </Typography>{' '}
    {children}
  </Box>
);

interface SummaryHeaderProps extends ContainersTabProps {
  onViewImages: () => void;
}

const SummaryHeader = ({ hostkey, onViewImages }: SummaryHeaderProps) => {
  const summary = useAppSelector(state => selectContainersSummary(state, hostkey));
  const loading = useAppSelector(state => selectContainersSummaryLoading(state, hostkey));

  if (loading && !summary) {
    return <CircularProgress size={20} />;
  }
  if (!summary) return null;

  return (
    <Box
      sx={{
        display: 'flex',
        alignItems: 'flex-start',
        flexWrap: 'wrap',
        gap: 26
      }}
    >
      <Box>
        <Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>
          <Typography component="h3" sx={{ fontSize: 23, fontWeight: 700 }}>
            Running containers
          </Typography>
          <Tooltip
            title="Container info is collected on hosts during CFEngine agent runs, using commands like docker ps, docker images, etc."
            arrow
          >
            <InfoIcon fontSize="small" sx={{ color: 'text.secondary', cursor: 'help' }} />
          </Tooltip>
        </Box>
        <Typography component="div" sx={{ fontSize: 44, fontWeight: 700, mt: 2 }}>
          {summary.containers.running}
        </Typography>
      </Box>
      <Box sx={{ color: 'text.secondary', fontSize: 14, fontWeight: 500 }}>
        {summary.last_collected_at && (
          <Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5, mb: 1.5, fontStyle: 'italic' }}>
            <AutorenewIcon fontSize="small" />
            Last updated: {formatRelativeTime(summary.last_collected_at)}
          </Box>
        )}
        <SummaryLine count={summary.images.named}>
          {pluralize('named image', summary.images.named)}{' '}
          <Link component="button" underline="hover" onClick={onViewImages}>
            View
          </Link>
        </SummaryLine>
        <SummaryLine count={summary.images.total}>
          {pluralize('image', summary.images.total)} in total (
          {formatBytes(summary.images.total_size_bytes)})
        </SummaryLine>
        <SummaryLine count={summary.volumes.count}>
          {pluralize('local volume', summary.volumes.count)} (
          {formatBytes(summary.volumes.total_size_bytes)})
        </SummaryLine>
        <Box>
          Container engines:{' '}
          <Typography component="span" sx={{ color: 'text.primary' }}>
            {summary.engines.length > 0 ? summary.engines.map(capitalize).join(', ') : '—'}
          </Typography>
        </Box>
      </Box>
    </Box>
  );
};

export const ContainersTab = ({ hostkey }: ContainersTabProps) => {
  const dispatch = useAppDispatch();
  const containers = useAppSelector(state => selectContainersList(state, hostkey));
  const images = useAppSelector(state => selectImagesList(state, hostkey));
  const imagesRef = useRef<HTMLDivElement>(null);

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

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

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

  return (
    <Box>
      <SummaryHeader
        hostkey={hostkey}
        onViewImages={() => imagesRef.current?.scrollIntoView({ behavior: 'smooth', block: 'start' })}
      />
      <Divider sx={{ my: '20px' }} />
      <PaginatedSection
        title="Containers"
        testId="containers"
        columns={containerColumns}
        list={containers}
        emptyText="No containers reported for this host."
        onChangePage={page => dispatch(setListPage({ hostkey, list: 'containers', page }))}
        onChangePerPage={perPage =>
          dispatch(setListPerPage({ hostkey, list: 'containers', perPage }))
        }
        onSort={sort => dispatch(setListSort({ hostkey, list: 'containers', sort }))}
      />
      <Divider sx={{ my: '20px' }} />
      <PaginatedSection
        title="Images"
        testId="images"
        columns={imageColumns}
        list={images}
        emptyText="No images reported for this host."
        sectionRef={imagesRef}
        onChangePage={page => dispatch(setListPage({ hostkey, list: 'images', page }))}
        onChangePerPage={perPage => dispatch(setListPerPage({ hostkey, list: 'images', perPage }))}
        onSort={sort => dispatch(setListSort({ hostkey, list: 'images', sort }))}
      />
    </Box>
  );
};
