import { useMemo } from 'react';

import Divider from '@material-hu/mui/Divider';
import Stack from '@material-hu/mui/Stack';
import { type SxProps, type Theme } from '@material-hu/mui/styles';
import Table from '@material-hu/mui/Table';
import TableBody from '@material-hu/mui/TableBody';
import TableCell from '@material-hu/mui/TableCell';
import TableContainer from '@material-hu/mui/TableContainer';
import TableHead from '@material-hu/mui/TableHead';
import TableRow from '@material-hu/mui/TableRow';
import Typography from '@material-hu/mui/Typography';

import {
  parseMarkdownBlocks,
  parseMarkdownInline,
  wrapInlineChildren,
} from './markdownParser';

const markdownTextColor = (theme: Theme) =>
  theme.palette.new.text.neutral.default;

const bodyTextSx: SxProps<Theme> = {
  color: markdownTextColor,
  lineHeight: 1.55,
};

const tableCellSx: SxProps<Theme> = {
  ...bodyTextSx,
  typography: 'globalXS',
  color: markdownTextColor,
  '&.MuiTableCell-root': { color: markdownTextColor },
  lineHeight: 1.4,
  py: 0.5,
  px: 1,
};

export type MarkdownContentProps = {
  markdown: string;
};

const MarkdownContent = ({ markdown }: MarkdownContentProps) => {
  const blocks = useMemo(() => parseMarkdownBlocks(markdown), [markdown]);

  return (
    <Stack
      component="article"
      sx={{
        width: '100%',
        textAlign: 'left',
        gap: 1.5,
        color: markdownTextColor,
      }}
    >
      {blocks.map((block, blockIndex) => {
        const bKey = `contract-block-${blockIndex}`;
        switch (block.type) {
          case 'hr':
            return (
              <Divider
                key={bKey}
                sx={{
                  borderColor: theme =>
                    theme.palette.new.border.neutral.divider,
                }}
              />
            );
          case 'h1':
            return (
              <Typography
                key={bKey}
                component="h1"
                variant="globalM"
                sx={{
                  ...bodyTextSx,
                  fontWeight: 'fontWeightBold',
                }}
              >
                {wrapInlineChildren(
                  parseMarkdownInline(block.text, `${hKey(blockIndex)}-h1`),
                )}
              </Typography>
            );
          case 'h2':
            return (
              <Typography
                key={bKey}
                component="h2"
                variant="globalS"
                sx={{
                  ...bodyTextSx,
                  fontWeight: 'fontWeightBold',
                }}
              >
                {wrapInlineChildren(
                  parseMarkdownInline(block.text, `${hKey(blockIndex)}-h2`),
                )}
              </Typography>
            );
          case 'h3':
            return (
              <Typography
                key={bKey}
                component="h3"
                variant="globalXS"
                sx={{
                  ...bodyTextSx,
                  fontWeight: 'fontWeightBold',
                }}
              >
                {wrapInlineChildren(
                  parseMarkdownInline(block.text, `${hKey(blockIndex)}-h3`),
                )}
              </Typography>
            );
          case 'p':
            return (
              <Typography
                key={bKey}
                component="p"
                variant="globalXS"
                sx={bodyTextSx}
              >
                {wrapInlineChildren(
                  parseMarkdownInline(block.text, `${hKey(blockIndex)}-p`),
                )}
              </Typography>
            );
          case 'blockquote':
            return (
              <Stack
                key={bKey}
                sx={{
                  borderLeft: 4,
                  borderColor: theme =>
                    theme.palette.new.border.neutral.default,
                  pl: 1.5,
                }}
              >
                {block.lines.map((line, li) => (
                  <Typography
                    key={`${bKey}-q-${li}`}
                    component="p"
                    variant="globalXS"
                    sx={{
                      ...bodyTextSx,
                      mb: li < block.lines.length - 1 ? 0.5 : 0,
                    }}
                  >
                    {wrapInlineChildren(
                      parseMarkdownInline(line, `${hKey(blockIndex)}-q-${li}`),
                    )}
                  </Typography>
                ))}
              </Stack>
            );
          case 'ul':
            return (
              <Stack
                key={bKey}
                component="ul"
                sx={{
                  m: 0,
                  pl: 2.5,
                  listStyleType: 'disc',
                  display: 'block',
                }}
              >
                {block.items.map((item, ii) => (
                  <Typography
                    key={`${bKey}-li-${ii}`}
                    component="li"
                    variant="globalXS"
                    sx={{ ...bodyTextSx, display: 'list-item', mb: 0.5 }}
                  >
                    {wrapInlineChildren(
                      parseMarkdownInline(item, `${hKey(blockIndex)}-ul-${ii}`),
                    )}
                  </Typography>
                ))}
              </Stack>
            );
          case 'ol':
            return (
              <Stack
                key={bKey}
                component="ol"
                sx={{
                  m: 0,
                  pl: 2.5,
                  listStyleType: 'decimal',
                  display: 'block',
                }}
              >
                {block.items.map((item, ii) => (
                  <Typography
                    key={`${bKey}-oli-${ii}`}
                    component="li"
                    variant="globalXS"
                    sx={{ ...bodyTextSx, display: 'list-item', mb: 0.5 }}
                  >
                    {wrapInlineChildren(
                      parseMarkdownInline(item, `${hKey(blockIndex)}-ol-${ii}`),
                    )}
                  </Typography>
                ))}
              </Stack>
            );
          case 'table': {
            const colCount = Math.max(
              block.headers.length,
              ...block.rows.map(r => r.length),
            );
            const headers = [...block.headers];
            while (headers.length < colCount) {
              headers.push('');
            }
            const rows = block.rows.map(row => {
              const cells = [...row];
              while (cells.length < colCount) {
                cells.push('');
              }
              return cells.slice(0, colCount);
            });
            return (
              <TableContainer
                key={bKey}
                sx={{
                  border: 1,
                  borderColor: theme =>
                    theme.palette.new.border.neutral.divider,
                  borderRadius: 1,
                  overflowX: 'auto',
                  maxWidth: '100%',
                }}
              >
                <Table
                  size="small"
                  sx={{ minWidth: 200, color: markdownTextColor }}
                >
                  <TableHead>
                    <TableRow>
                      {headers.map((h, hi) => (
                        <TableCell
                          key={`${bKey}-th-${hi}`}
                          sx={{
                            ...tableCellSx,
                            fontWeight: 'fontWeightBold',
                            borderColor: theme =>
                              theme.palette.new.border.neutral.divider,
                          }}
                        >
                          {wrapInlineChildren(
                            parseMarkdownInline(
                              h,
                              `${hKey(blockIndex)}-th-${hi}`,
                            ),
                          )}
                        </TableCell>
                      ))}
                    </TableRow>
                  </TableHead>
                  <TableBody>
                    {rows.map((row, ri) => (
                      <TableRow key={`${bKey}-tr-${ri}`}>
                        {row.map((cell, ci) => (
                          <TableCell
                            key={`${bKey}-td-${ri}-${ci}`}
                            sx={{
                              ...tableCellSx,
                              borderColor: theme =>
                                theme.palette.new.border.neutral.divider,
                            }}
                          >
                            {wrapInlineChildren(
                              parseMarkdownInline(
                                cell,
                                `${hKey(blockIndex)}-td-${ri}-${ci}`,
                              ),
                            )}
                          </TableCell>
                        ))}
                      </TableRow>
                    ))}
                  </TableBody>
                </Table>
              </TableContainer>
            );
          }
          default:
            return null;
        }
      })}
    </Stack>
  );
};

function hKey(blockIndex: number): string {
  return `cb-${blockIndex}`;
}

export default MarkdownContent;
