'use client';

import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import {
  AutoAwesome as AutoAwesomeIcon,
  ContentCopy as ContentCopyIcon,
  SaveAlt as SaveAltIcon,
  OpenInNew as OpenInNewIcon
} from '@mui/icons-material';
import { Message, USER_TYPE, updateMessageReport } from '../store/chatSlice';
import { format } from 'sql-formatter';
import { Box, Table, TableBody, TableHead, TableRow, TableCell, Link, Button, IconButton, Tooltip } from '@mui/material';
import { makeStyles } from 'tss-react/mui';
import SaveReport from '../../common/SaveReportDialog';
import { useDispatch, useSelector } from 'react-redux';
import { handleCopy } from '../../../utils';

import {
  Accordion,
  AccordionSummary,
  AccordionDetails,
  Typography
} from '@mui/material';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import { SaveReportRequest } from '../../../store/reportsSlice/thunks';
import { selectUserRoles } from './../store/chatSlice/selectors';

const useStyles = makeStyles()(theme => ({
  chatContainer: {
    flex: 1,
    padding: '1rem',
    display: 'flex',
    flexDirection: 'column',
    paddingRight: theme.spacing(2),
    '& .MuiTable-root': {
      border: 'none'
    },
    '& .MuiTableCell-root': {
      height: 32
    }
  },
  message: {
    marginBottom: theme.spacing(4),
  },
  messageText: {
    fontSize: 16,
    lineHeight: '24px',
    fontWeight: 400
  },
  messageUser: {
    alignSelf: 'flex-end',
    backgroundColor: theme.palette.darkBlue[600],
    padding: '8px 12px 8px 12px',
    color: 'white',
    borderRadius: 4
  },
  messageBot: {
    alignSelf: 'flex-start',
  },
  thinking: {
    animation: 'pulse 1.5s ease-in-out infinite',
    marginRight: 12,
    fontSize: 22
  },
  generatedBy: {
    fontSize: 12,
    color: theme.palette.text.secondary,
    fontWeight: 400,
    letterSpacing: '0.4px',
  },
  accordion: {
    boxShadow: 'none',
    background: 'transparent',
    border: `1px solid ${theme.palette.primary.border}`
  },
  accordionSummary: {
    background: 'transparent',
    boxShadow: 'none',
    height: 40,
    minHeight: 40,
    '&.Mui-expanded': {
      borderBottom: `1px solid ${theme.palette.primary.border}`,
      height: 40,
      minHeight: 40,
    }
  },
  accordionDetails: {
    padding: 0,
    position: 'relative'
  },
  pre: {
    border: 'none',
    fontFamily: 'Red Hat Mono',
    fontSize: 13
  },
  reportBlock: {
    fontWeight: 400,
    display: 'flex',
    'a': {
      fontWeight: 500,
      color: theme.palette.blue[600],
      textDecoration: 'none'
    }
  },
  viewMore: {
    fontWeight: 400,
    color: theme.palette.blue[600],
    textDecoration: 'none',
    paddingTop: theme.spacing(0.5),
    paddingLeft: theme.spacing(2),
    display: 'block'
  },
  actionButtons: {
    'button': {
      color: theme.palette.text.primary,
      opacity: .6,
      minWidth: 35
    }
  },
  copyButton: {
    position: 'absolute',
    top: 8,
    right: 8,
    zIndex: 10
  }
}));

const Messages = ({ isLoading, messages, minimize }) => {
  const { classes } = useStyles();

  const renderedMessages = useMemo(
    () => messages.map((message: Message) =>
      (message.sender === USER_TYPE ? <UserMessage message={message} classes={classes} /> : <AgentReply message={message} classes={classes} minimize={minimize} />))
    , [messages]
  );

  return (
    <Box className={classes.chatContainer}>
      {renderedMessages}
      {isLoading && (
        <Box className={`${classes.message} ${classes.messageBot} flex flex--align_center`}>
          <Box className="flex flex--align_start" sx={{ ml: -4 }}>
            <AutoAwesomeIcon
              color='primary'
              className={classes.thinking}
            />
          </Box>
          Thinking
        </Box>
      )}
    </Box>
  )
};

const AgentReply = ({ message, classes, minimize }: { message: Message, classes: {}, minimize: () => void }) => {
  const dispatch = useDispatch();
  const userRoles = useSelector(selectUserRoles);
  const tableRef = useRef(null);

  const [saveReportOpen, setSaveReportOpen] = useState(false);
  const handleSaveReportOpen = () => setSaveReportOpen(true);
  const handleSaveReportClose = () => setSaveReportOpen(false);


  if (typeof message.payload === 'string') {
    return (
      <Box key={message.id} className={`${classes.message} ${classes.messageBot}`}>
        <Box className="flex flex--align_start" sx={{ mb: 2, ml: -4 }}>
          <AutoAwesomeIcon color='primary' sx={{ fontSize: 22, mr: 1 }} />
          <Box className={classes.messageText}>{message.payload}</Box>
        </Box>
      </Box>
    );
  }

  const { data = {}, explanation, sql, reportLink, meta = {} } = message.payload;
  const { headers, rows, total } = data;
  const { model = '', provider = '' } = meta;
  const moreItems = total - 10;

  const handleViewMore = () => {
    minimize();
    document.location.href = reportLink;
  };

  const handleReportSaved = (savedReport: SaveReportRequest) => {
    dispatch(updateMessageReport({ messageId: message.id, report: savedReport }));
  }

  const onCopy = () => {
    handleCopy(`${explanation}\n\nData:\n${tableRef.current.innerText}\n\nSQL:\n${sql}`);
    notify.success('Copied.');
  }

  return (
    <Box key={message.id} className={`${classes.message} ${classes.messageBot}`}>
      <Box className="flex flex--align_start" sx={{ mb: 2, ml: -4 }}>
        <AutoAwesomeIcon color='primary' sx={{ fontSize: 22, mr: 1 }} />
        <Box className={classes.messageText}>{explanation}</Box>
      </Box>
      <Table sx={{ minWidth: 650 }} ref={tableRef}>
        <TableHead>
          <TableRow>
            {headers.map((header, i) => (
              <TableCell key={i}> {header}</TableCell>
            ))}
          </TableRow>
        </TableHead>
        <TableBody>
          {rows.map(row => (
            <TableRow key={row.name}>
              {row.map((cell, cellIndex) => (
                <TableCell key={cellIndex}>{cell}</TableCell>
              ))}
            </TableRow>
          ))}
        </TableBody>
      </Table>
      {(moreItems > 0) &&
        <Box>
          <Button className={classes.viewMore} onClick={handleViewMore}>
            View more +{moreItems}
          </Button>
        </Box>}
      <Box sx={{ mt: 2 }} className="flex flex-space-between flex--align_center">
        <Box className={classes.actionButtons}>
          <Button onClick={handleSaveReportOpen}><Tooltip title="Save as report"><SaveAltIcon sx={{ fontSize: 18 }} /></Tooltip></Button>
          <Button onClick={onCopy} ><ContentCopyIcon sx={{ fontSize: 18 }} /></Button>
        </Box>
        <Box className={classes.generatedBy}>Response generated by {provider}/{model}</Box>
      </Box>
      {message.report &&
        <Box className={classes.reportBlock} sx={{ mt: 2 }}>
          This query was saved as a report: <Link className="flex" sx={{ ml: 1 }} target="_blank" href={`/reports/report/run/${message.report.id}/`}>{message.report.search_name} <OpenInNewIcon sx={{ ml: 1, fontSize: 18 }} /></Link>
        </Box>}
      <Box sx={{ mt: 2 }}>
        <ShowSQLAccordion SQL={sql} />
      </Box>
      <SaveReport sql={sql} onSave={handleReportSaved} userRoles={userRoles} open={saveReportOpen} onClose={handleSaveReportClose} />
    </Box>
  );
}

const UserMessage = ({ message, classes }) => {
  return (
    <div key={message.id} className={`${classes.message} ${classes.messageUser} ${classes.messageText}`}>
      {message.payload}
    </div>
  );
}

const ShowSQLAccordion = ({ SQL }) => {
  const { classes } = useStyles();
  const formattedSQL = format(SQL, {
    language: 'postgresql',
    uppercase: true,
    tabWidth: 2,
    useTabs: false
  });

  const handleCopySQL = useCallback(() => {
    handleCopy(formattedSQL);
    notify.success('Copied.');
  }, [formattedSQL])

  return (
    <Box>
      <Accordion className={classes.accordion}>
        <AccordionSummary className={classes.accordionSummary} expandIcon={<ExpandMoreIcon />} sx={{ flexDirection: 'row-reverse' }}>
          <Typography variant="body2" sx={{ ml: 2 }}>
            Show SQL
          </Typography>
        </AccordionSummary>
        <AccordionDetails className={classes.accordionDetails}>

          <IconButton
            className={classes.copyButton}
            onClick={handleCopySQL}
            size="small"
            disabled={!formattedSQL}
          >
            <ContentCopyIcon fontSize="small" />
          </IconButton>

          <Typography component="pre" className={classes.pre}>
            {formattedSQL}
          </Typography>
        </AccordionDetails>
      </Accordion>
    </Box>
  );
};

export default Messages;
