import {
  Avatar,
  Button,
  Card,
  DialogActions,
  DialogContent,
  DialogTitle,
  Grid2 as Grid,
  Typography
} from "@mui/material";
import { AttachFile, Person, Visibility } from "@mui/icons-material";
import FileUploader from "common/FileUploads/FileUploader";
import ResponsiveDialog from "common/ResponsiveDialog";
// import { getTableIcons } from "common/ResponsiveTable";
// import MaterialTable, { Column } from "material-table";
import { Bin } from "models";
import { Contract } from "models/Contract";
import { GrainBag } from "models/GrainBag";
import { Transaction } from "models/Transaction";
import moment from "moment";
import ObjectDescriber from "objects/ObjectDescriber";
import DeleteIcon from "products/AgIcons/Delete";
import { pond } from "protobuf-ts/pond";
import { useBinAPI, useGlobalState, useGrainBagAPI, useSnackbar, useTransactionAPI, useUserAPI } from "providers";
import React, { useEffect, useState } from "react";
import TransactionDataDisplay from "transactions/transactionDataDisplay";
import ContractTransactionFile from "./contractTransactionFile";
import { makeStyles } from "@mui/styles";
import ResponsiveTable, { Column } from "common/ResponsiveTable";
import { cloneDeep } from "lodash";

interface Props {
  contract: Contract;
  permissions: pond.Permission[];
  transactions: Transaction[];
  objectNames: Map<string, string>;
  transactionRevokedCallback: (transactionKey: string) => void;
}

const useStyles = makeStyles(() => ({
    userAvatar: {
      width: 36,
      height: 36
    }
  })
);

export default function ContractTransactionTable(props: Props) {
  const { transactions, objectNames, contract, permissions, transactionRevokedCallback } = props;
  const [tableData, setTableData] = useState<Transaction[]>([]);
  const [displayData, setDisplayData] = useState<Transaction[]>([]);
  const [tablePage, setTablePage] = useState(0)
  const [pageSize, setPageSize] = useState(10)
  const [{as}] = useGlobalState();
  const userAPI = useUserAPI();
  const [userProfiles, setUserProfiles] = useState<Map<string, pond.UserProfile>>(new Map());
  const [openRevokeDialog, setOpenRevokeDialog] = useState(false);
  const classes = useStyles();
  const [activeTransaction, setActiveTransaction] = useState<Transaction>(Transaction.create());
  const transactionAPI = useTransactionAPI();
  const binAPI = useBinAPI();
  const bagAPI = useGrainBagAPI();
  const [transactionSource, setTransactionSource] = useState<Bin | GrainBag | undefined>(undefined);
  const [openFileViewer, setOpenFileViewer] = useState(false);
  const [openAttachmentDialog, setOpenAttachmentDialog] = useState(false);
  const [selectedTransaction, setSelectedTransaction] = useState<Transaction>(Transaction.create());
  const [attachmentList, setAttachmentList] = useState<string[]>([]);
  const [uploading, setUploading] = useState(false);
  const { openSnack } = useSnackbar();

  useEffect(() => {
    let users: string[] = [];
    transactions.forEach(transaction => {
      if (
        !users.includes(transaction.transaction.userId) &&
        transaction.transaction.userId !== "unknown"
      ) {
        users.push(transaction.transaction.userId);
      }
    });
    setTableData(transactions);
    userAPI.getProfiles(users).then(resp => {
      let userMap: Map<string, pond.UserProfile> = new Map<string, pond.UserProfile>();
      resp.forEach(profile => {
        userMap.set(profile.id, profile);
      });
      setUserProfiles(userMap);
    });
  }, [transactions, userAPI]);

  useEffect(()=>{
    let clone: Transaction[] = cloneDeep(tableData)
    let rows = clone.splice(tablePage * pageSize, pageSize)
    setDisplayData(rows)
  },[tablePage, pageSize, tableData])

  const getTransactionSource = (transaction: Transaction) => {
    setTransactionSource(undefined);
    switch (transaction.transaction.fromObject) {
      case pond.ObjectType.OBJECT_TYPE_BIN:
        binAPI.getBin(transaction.transaction.fromKey, as).then(resp => {
          let bin = Bin.create(resp.data);
          setTransactionSource(bin);
        });
        break;
      case pond.ObjectType.OBJECT_TYPE_GRAIN_BAG:
        bagAPI.getGrainBag(transaction.transaction.fromKey, as).then(resp => {
          if (resp.data.grainBag) {
            let bag = GrainBag.create(resp.data.grainBag);
            setTransactionSource(bag);
          }
        });
        break;
    }
  };

  const canRevoke = () => {
    let valid = true;
    if (transactionSource) {
      const amount = activeTransaction.transaction.transaction?.grainTransaction?.bushels ?? 0;
      switch (activeTransaction.transaction.fromObject) {
        case pond.ObjectType.OBJECT_TYPE_BIN:
          const bin = transactionSource as Bin;
          const inv = bin.settings.inventory;
          const specs = bin.settings.specs;
          if (inv && specs) {
            if (inv.grainBushels + amount > specs.bushelCapacity) {
              valid = false;
            }
          }
          break;
        case pond.ObjectType.OBJECT_TYPE_GRAIN_BAG:
          const bag = transactionSource as GrainBag;
          if (bag.bushels() + amount > bag.capacity()) {
            valid = false;
          }
          break;
      }
    }
    return valid;
  };

  const revokeTransaction = () => {
    //use the transaction api to revoke the transaction
    //--moved all the functionality for adjusting the objects involved to the backend so this can be handled with a single call--
    transactionAPI
      .revokeTransaction(activeTransaction.transaction.key, as)
      .then(resp => {
        openSnack("Transaction revoked and inventory moved back");
        transactionRevokedCallback(activeTransaction.transaction.key);
      })
      .catch(err => {
        openSnack("There was was a problem revoking the transaction");
      });
  };

  const revokeDialog = () => {
    return (
      <ResponsiveDialog
        open={openRevokeDialog}
        onClose={() => {
          setOpenRevokeDialog(false);
        }}>
        <DialogTitle>Revoke Transaction</DialogTitle>
        <DialogContent>
          Revoking this transaction will return the grain from the contract to its origin.
        </DialogContent>
        <DialogActions>
          <Button
            onClick={() => {
              setOpenRevokeDialog(false);
            }}>
            Cancel
          </Button>
          <Button
            onClick={() => {
              revokeTransaction();
              setOpenRevokeDialog(false);
            }}
            disabled={!canRevoke()}>
            Confirm
          </Button>
        </DialogActions>
      </ResponsiveDialog>
    );
  };

  const displayUser = (userID: string) => {
    let profile = userProfiles.get(userID);
    if (profile) {
      return (
        <Grid container direction="row" alignItems="center" spacing={2}>
          <Grid>
            {profile.avatar ? (
              <Avatar alt={profile.name} src={profile.avatar} className={classes.userAvatar}>
                {!profile.avatar && profile.name}
              </Avatar>
            ) : (
              <Avatar alt={profile.name} className={classes.userAvatar}>
                <Person />
              </Avatar>
            )}
          </Grid>
          <Grid>
            <Typography>{profile.name}</Typography>
          </Grid>
        </Grid>
      );
    } else {
      return (
        <Grid container direction="row" alignItems="center" spacing={2}>
          <Grid>
            <Avatar alt={"unknownUser"} className={classes.userAvatar}>
              <Person />
            </Avatar>
          </Grid>
          <Grid>
            <Typography>Unknown</Typography>
          </Grid>
        </Grid>
      );
    }
  };

  const attachmentDialog = () => {
    return (
      <ResponsiveDialog
        open={openAttachmentDialog}
        onClose={() => {
          setOpenAttachmentDialog(false);
        }}>
        <DialogTitle>Select Files to Upload</DialogTitle>
        <DialogContent>
          <FileUploader
            keys={[contract.key(), selectedTransaction.transaction.key]}
            types={["contract", "transaction"]}
            toAttach={{
              key: selectedTransaction.transaction.key,
              type: pond.ObjectType.OBJECT_TYPE_TRANSACTION
            }}
            uploadStart={() => {
              //disable close button
              setUploading(true);
            }}
            uploadEnd={fileID => {
              let aL = attachmentList;
              //update the transaction with the new fileID
              setUploading(false);
              if (fileID) {
                aL.push(fileID);
              }
              setAttachmentList(aL);
            }}
          />
        </DialogContent>
        <DialogActions>
          <Button
            disabled={uploading}
            onClick={() => {
              setOpenAttachmentDialog(false);
            }}>
            Close
          </Button>
          {/* <Button
            disabled={uploading}
            onClick={() => {
              updateTransaction();
            }}>
            Attach Files
          </Button> */}
        </DialogActions>
      </ResponsiveDialog>
    );
  };

  const columns: Column<Transaction>[] = [
    {
      title: "Date",
      render: row => {
        return <Typography>{moment(row.transaction.timestamp).format("YYYY-MM-DD")}</Typography>;
      }
    },
    {
      title: "User",
      render: row => {
        return displayUser(row.transaction.userId);
      }
    },
    {
      title: "Source",
      render: row => {
        return (
          <React.Fragment>
            <Typography>{ObjectDescriber(row.transaction.fromObject).name}</Typography>
            <Typography>
              {objectNames ? objectNames.get(row.transaction.fromKey) : row.transaction.fromKey}
            </Typography>
          </React.Fragment>
        );
      }
    },
    {
      title: "Transaction",
      render: row => {
        return <TransactionDataDisplay transaction={row} />;
      }
    },
    //this column should be hidden from users that dont have edit permissions to the contract
    {
      title: "Revoke Transaction",
      render: row => {
        return (
          <Button
            variant="contained"
            disabled={!permissions.includes(pond.Permission.PERMISSION_WRITE)}
            style={{ backgroundColor: "red" }}
            onClick={() => {
              setActiveTransaction(row);
              getTransactionSource(row);
              setOpenRevokeDialog(true);
            }}>
            <DeleteIcon />
          </Button>
        );
      }
    },
    {
      title: "Attachments",
      render: row => {
        return (
          <Grid container direction="row" spacing={2}>
            <Grid>
              <Button
                variant="contained"
                disabled={!permissions.includes(pond.Permission.PERMISSION_FILE_MANAGEMENT)}
                //style={{ backgroundColor: "red" }}
                onClick={() => {
                  setSelectedTransaction(row);
                  setOpenFileViewer(true);
                }}>
                <Visibility />
              </Button>
            </Grid>
            <Grid>
              <Button
                variant="contained"
                disabled={!permissions.includes(pond.Permission.PERMISSION_FILE_MANAGEMENT)}
                onClick={() => {
                  setSelectedTransaction(row);
                  setOpenAttachmentDialog(true);
                }}>
                <AttachFile />
              </Button>
            </Grid>
          </Grid>
        );
      }
    }
  ];

  return (
    <React.Fragment>
      <Card>
        <ResponsiveTable<Transaction> 
          page={tablePage}
          pageSize={pageSize}
          rows={displayData}
          columns={columns}
          total={tableData.length}
          handleRowsPerPageChange={(e)=>{setPageSize(e.target.value)}}
          setPage={(page)=>{setTablePage(page)}}
          loadMore={()=>{
            let clone: Transaction[] = cloneDeep(tableData)
            let current = cloneDeep(displayData)
            let newRows = clone.splice(current.length, pageSize)
            setDisplayData(current.concat(newRows))
          }}
        />
        {/* <MaterialTable
          title={"Deliveries"}
          columns={columns}
          data={tableData}
          icons={getTableIcons()}
        /> */}
      </Card>
      <ContractTransactionFile
        contractKey={contract.key()}
        transactionKey={selectedTransaction.transaction.key}
        open={openFileViewer}
        onClose={() => {
          setOpenFileViewer(false);
        }}
      />
      {revokeDialog()}
      {attachmentDialog()}
    </React.Fragment>
  );
}
