import {
  Card,
  CardContent,
  CardHeader,
  Typography,
  CardActions,
  Button,
  TableContainer,
  Table,
  TableBody,
  TableHead,
  TableCell,
  TableRow
} from '@mui/material';
import { withStyles, createStyles } from '@mui/styles';
import makeStyles from '@mui/styles/makeStyles';
import { PConnProps } from '@pega/react-sdk-components/lib/types/PConnProps';

import Styled{{COMPONENT_CLASS_NAME}}Wrapper from './styles';
import isDeepEqual from 'fast-deep-equal/react';
import { Utils } from '@pega/react-sdk-components/lib/components/helpers/utils';
import { useRef, useEffect, useState } from 'react';
import { Theme as MuiTheme } from "@mui/material/styles";

declare module "@mui/private-theming" {
  interface DefaultTheme extends MuiTheme {
    spacing: (spacing: number) => string;
  }
}

interface {{COMPONENT_CLASS_NAME}}Props extends PConnProps {
  // If any, enter additional props that only exist on this component
  header?: string;
  description?: string;
  datasource?: any;
  whatsnewlink?: string;
}

const useStyles = makeStyles(myTheme => ({
  root: {
    marginTop: myTheme.spacing(1),
    marginBottom: myTheme.spacing(1),
    borderLeft: '6px solid',
    borderLeftColor: myTheme.palette.primary.light
  }
}));

const StyledTableCell = withStyles((myTheme) =>
  createStyles({
    head: {
      borderWidth: '1px',
      borderStyle: 'solid',
      borderColor: 'silver',
      backgroundColor: myTheme.palette.text.disabled,
      color: myTheme.palette.getContrastText(myTheme.palette.text.disabled)
    },
    body: {
      borderWidth: '1px',
      borderStyle: 'solid',
      borderColor: 'silver'
      // fontSize: 14,
    }
  })
)(TableCell);

// Page Widget example is the "App Announcment"

// props passed in combination of props from property panel (config.json) and run time props from Constellation
export default function {{COMPONENT_CLASS_NAME}}(props: {{COMPONENT_CLASS_NAME}}Props) {
  const { header = '', description = '', datasource = [], whatsnewlink = '', getPConnect } = props;
  let details = [];
  if (datasource && datasource.source) {
    details = datasource.source.map(item => {
      return item.name;
    });
  }

  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  const [waitingForData, setWaitingForData] = useState<boolean>(true);
  const thePConn = getPConnect();
  const caseID = thePConn.getValue(PCore.getConstants().CASE_INFO.CASE_INFO_ID, ''); // 2nd arg empty string until typedef marked correctly
  const dataViewName = 'D_pyMyWorkList';
  const context = thePConn.getContextName();

  const rowData: any = useRef([]);

  const classes = useStyles();

  const displayedColumns = [
    {
      label: thePConn.getLocalizedValue('Case type', '', ''),
      type: 'TextInput',
      fieldName: 'pxProcessName'
    }, // 2nd and 3rd args empty string until typedef marked correctly
    {
      label: thePConn.getLocalizedValue('Key', '', ''),
      type: 'TextInput',
      fieldName: 'pxRefObjectInsName'
    }, // 2nd and 3rd args empty string until typedef marked correctly
    {
      label: thePConn.getLocalizedValue('Status', '', ''),
      type: 'TextInput',
      fieldName: 'pyAssignmentStatus'
    }, // 2nd and 3rd args empty string until typedef marked correctly
    {
      label: thePConn.getLocalizedValue('Stage', '', ''),
      type: 'TextInput',
      fieldName: 'pxTaskLabel'
    } // 2nd and 3rd args empty string until typedef marked correctly
  ];

  function computeRowData(rows: object[]): void {
    const theRowData: object[] = [];

    rows?.forEach((row: any, rowIndex: number) => {
      // Now, for each property in the index of row properties (displayedColumns), add an object
      //  to a new array of values
      const rowDisplayValues: any = [];

      displayedColumns.forEach((column: any, rowValIndex) => {
        const theType = column.type;
        const theFieldName = column.fieldName;
        const theValue =
          theType === 'Date' || theType === 'DateTime' ? Utils.generateDateTime(row[theFieldName], 'DateTime-Short') : row[theFieldName];
        rowDisplayValues[rowValIndex] = theValue;
      });

      theRowData[rowIndex] = rowDisplayValues;
    });

    if (!isDeepEqual(theRowData, rowData.current)) {
      // Only update rowData.current when it actually changes (to prevent infinite loop)
      rowData.current = theRowData;
    }
  }

  const handleClick = () => {
    window.open(whatsnewlink);
  };

  // Get the case history data when component mounted/initialized
  useEffect(() => {
    let bCallSetWaitingForData = true;

    const worklistData = PCore.getDataApiUtils().getData(
      dataViewName,
      { dataViewParameters: [{ CaseInstanceKey: caseID }] } as any,
      context
    ) as Promise<any>;

    worklistData.then((worklistJSON: any) => {
      const tableDataResults = worklistJSON.data.data;

      // compute the rowData using the tableDataResults
      computeRowData(tableDataResults);

      // At this point, if we have data ready to render and haven't been asked
      //  to NOT call setWaitingForData, we can stop progress indicator
      if (bCallSetWaitingForData) {
        setWaitingForData(false);
      }
    });

    return () => {
      // Inspired by https://juliangaramendy.dev/blog/use-promise-subscription
      // The useEffect closure lets us have access to the bCallSetWaitingForData
      //  variable inside the useEffect and inside the "then" clause of the
      //  historyData promise
      //  So, if this cleanup code gets run before the promise .then is called,
      //  we can avoid calling the useState setter which would otherwise show a warning
      bCallSetWaitingForData = false;
    };
  }, []);

  function getTableHeader() {
    const theRowKey = 'CaseHistory.TableHeader';

    const theHeaderCells: any[] = displayedColumns.map((headerCol, index) => {
      const theCellKey = `${theRowKey}.${index}`;
      return <StyledTableCell key={theCellKey}>{headerCol.label}</StyledTableCell>;
    });

    return <TableRow key={theRowKey}>{theHeaderCells}</TableRow>;
  }

  function getTableData() {
    const theDataRows: any[] = [];

    // Note: using rowData.current since we're using useRef as a mutatable
    //  value that's only updated when it changes.
    if (rowData.current.length > 0) {
      rowData.current.forEach((dataRow: object[], index) => {
        // using dataRow[0]-dataRow[1] as the array key since it's a unique value
        const theKey = `CaseHistory-${index}`;
        theDataRows.push(
          <TableRow key={theKey}>
            <StyledTableCell>{dataRow[0] ? (dataRow[0]) : '---' as any}</StyledTableCell>
            <StyledTableCell>{dataRow[1] ? (dataRow[1]) : '---' as any}</StyledTableCell>
            <StyledTableCell>{dataRow[2] ? (dataRow[2]) : '---' as any}</StyledTableCell>
            <StyledTableCell>{dataRow[3] ? (dataRow[3]) : '---' as any}</StyledTableCell>
          </TableRow>
        );
      });
    }
    return theDataRows;
  }

  return (
    <Styled{{COMPONENT_CLASS_NAME}}Wrapper>
      <Card title='AppAnnouncement' className={classes.root}>
        <CardHeader title={<Typography variant='h6'>{header}</Typography>} />
        <CardContent>
          <Typography variant='body1' gutterBottom>
            {description}
          </Typography>
          {details.map((itm, idx) => {
            const theKey = `AppAnn-item-${idx}`;
            return (
              <Typography key={theKey} variant='body2'>
                - {itm}
              </Typography>
            );
          })}
        </CardContent>
        <CardActions>
          <Button color='primary' onClick={handleClick} size='small'>
            See what&apos;s new
          </Button>
        </CardActions>
      </Card>
      <TableContainer>
        <Table>
          <TableHead>{getTableHeader()}</TableHead>
          <TableBody>{getTableData()}</TableBody>
        </Table>
      </TableContainer>
    </Styled{{COMPONENT_CLASS_NAME}}Wrapper>
  );
}
