import * as React from "react";
import { useEffect, useState } from "react";
import Box from "@mui/material/Box";
import Typography from "@mui/material/Typography";
import Grid from "@mui/material/Grid";
import Paper from "@mui/material/Paper";
import SignTable from "../../components/tables/SignTable";
import Button from "@mui/material/Button";
import SelectField from "../../components/SelectField";
import {
  fetchEmailByID,
  fetchEmailStatistics,
  updateEmail,
} from "../../helpers/emails";
import { fetchSigns } from "../../helpers/signs";
import { fetchTypes } from "../../helpers/types";
import { useHistory } from "react-router-dom";
import ReactHtmlParser from "react-html-parser";
import ErrorBox from "../../components/ErrorBox";

const emailInit = {
  id: -1,
  subject: "",
  sender: "",
  recipient: "",
  date: "",
  cc: "",
  body: "",
  type: { id: -1, type: "" },
  sign: [],
};
// TODO kontrolovat aby nepriradil legitimate znaky
// Page where email info is displayed,
// admin can also add/remove type and signs of this email
export default function EmailInfoPage({ match }) {
  // email with id from match
  const [email, setEmail] = useState(emailInit);
  // email statistics
  const [emailStats, setEmailStats] = useState({
    occurrence: "",
    average_duration: "",
    average_correctness: "",
  });
  // all types
  const [types, setTypes] = React.useState([]);
  const [allSigns, setAllSigns] = useState([]);
  // IDs of signs selected in SelectField, can be assigned to email
  const [selectedSignsIDs, setSelectedSignsIDs] = useState([]);
  // all unassigned signs to this email
  const [unassignedSigns, setUnassignedSigns] = useState([]);
  const emailId = match.params.id;
  const history = useHistory();
  // hook for checking if email is loading
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState("")

  // on page mount fetch email and
  // statistics of the current email and also all types and signs
  useEffect(() => {
    fetchEmailByID(emailId).then((res) => {
      setEmail(res);
      setIsLoading(false);
    });
    fetchTypes().then((res) => setTypes(res));
    fetchSigns().then((res) => setAllSigns(res));

    fetchEmailStatistics(emailId).then((res) => {
      setEmailStats({
        ...res,
        // add % to value of average correctness statistic
        "Average correctness": res["Average correctness"] + "%",
      });
    });
  }, [emailId]);

  // when email or signs are updated, update unassigned signs
  useEffect(() => {
    const unassigned = allSigns.filter(
      (sign) => email.sign.indexOf(sign) === -1
    );
    setUnassignedSigns(unassigned);
  }, [email, allSigns]);

  // TODO error if type is legitimate and signs are assigned
  function handleChangeType(type_id) {
    const type = types.find((type) => type.id === type_id); // find selected type by id

    setEmail({ ...email, type: { ...type } });
  }

  // handler is called when user clicks on save button
  function handleUpdate() {
    if(email.type.id === 1 && email.sign.length > 0){
      setError("Legitimate email cannot have phishing signs!")
      return
    } else if( email.type.id !== 1 && email.sign.length === 0 ){
      setError("Phishing email has to own at least one phishing sign!")
      return
    }

    const data = {
      ...email,
      type: email.type.id, // parse object type to type id
      sign: email.sign.map((sign) => sign.id), // parse array of sign objects into array of sign IDs
    };

    updateEmail(email.id, data).then((_) => history.goBack());
  }

  // handler for assigning signs to email, is called when Add button is clicked
  function handleAddSigns() {
    // parse selected IDs to Sign objects
    const selected = unassignedSigns.filter(
      (sign) => selectedSignsIDs.indexOf(sign.id) !== -1
    );

    // assign signs to email
    setEmail({ ...email, sign: [...email.sign, ...selected] });
    setSelectedSignsIDs([]);
  }

  // paper containing statistic's key and value
  const statisticsPaper = (key, value, index) => {
    return (
      <Paper
        key={index}
        elevation={4}
        sx={{
          display: "flex",
          flexDirection: "column",
          width: 160,
          height: 100,
          alignItems: "center",
          justifyContent: "center",
          backgroundColor: "#019592",
        }}
      >
        <Typography variant="h5"> {value}</Typography>
        <Typography>{key}</Typography>
      </Paper>
    );
  };

  // row containing key and value of email info
  const emailInfoRow = (key, value, index) => {
    return (
      <Grid item container spacing={1} key={index}>
        <Grid item xs={3} sm={2}>
          <Typography
            sx={{
              textAlign: "right",
              overflowWrap: "break-word",
            }}
          >
            {key}:
          </Typography>
        </Grid>
        <Grid item xs={9} sm={10}>
          <Typography
            sx={{
              overflowWrap: "break-word",
              maxHeight: 200,
              overflow: "auto",
            }}
          >
            {ReactHtmlParser(value)}
          </Typography>
        </Grid>
      </Grid>
    );
  };

  // if email data are fetching, show loading text
  if (isLoading) {
    return <Typography>Loading...</Typography>;
  }

  return (
    <Box>
      <ErrorBox severity="error" error={error} setError={setError}/>
      {/* Box for all email statistics, statistics are mapped inside into Paper */}
      <Box
        sx={{
          display: "flex",
          flexDirection: { xs: "column", sm: "row" },
          alignItems: "center",
          justifyContent: "space-evenly",
          mt: 5,
        }}
      >
        {
          // statistics mapped into Paper
          Object.entries(emailStats).map(([key, value], index) => {
            return statisticsPaper(key, value, index);
          })
        }
      </Box>
      {/* column for info about email */}
      <Grid container direction="column" spacing={3} marginY={4}>
        {
          // map infos ( signs and type not included ) into row
          // for example: key="subject",value="send credentials" => "subject: send credentials"
          Object.entries(email)
            .slice(0, 8)
            .map(([key, value], index) => {
              return emailInfoRow(key, value, index);
            })
        }
        {/* Grid container for SelectField with type */}
        <Grid item container spacing={1} alignItems="center">
          <Grid item xs={3} sm={2}>
            <Typography
              sx={{
                textAlign: "right",
              }}
            >
              Type:
            </Typography>
          </Grid>
          <Grid item xs={9} sm={10}>
            <Box sx={{ maxWidth: 170 }}>
              <SelectField
                label="Type"
                name="Type"
                onChange={(e) => handleChangeType(e.target.value)}
                value={email.type.id}
                options={types}
              />
            </Box>
          </Grid>
        </Grid>
        {/* container for SelectField with signs */}
        <Grid item container spacing={1} alignItems="center">
          <Grid item xs={3} sm={2}>
            <Typography
              sx={{
                textAlign: "right",
                overflowWrap: "break-word",
              }}
            >
              Signs:
            </Typography>
          </Grid>
          <Grid item container xs={9} sm={10} alignItems="center">
            <Box sx={{ width: 170 }}>
              <SelectField
                label="Add sign"
                value={selectedSignsIDs}
                onChange={(e) => setSelectedSignsIDs(e.target.value)}
                options={unassignedSigns}
                multiple
                name="Sign"
              />
            </Box>
            {/* if button is clicked, assign selected signs to email */}
            <Button
              variant="contained"
              size="medium"
              onClick={handleAddSigns}
              sx={{ ml: 4 }}
            >
              Add
            </Button>
          </Grid>
        </Grid>
      </Grid>
      <SignTable
        signs={email.sign}
        // on delete selected signs are unassigned from email
        handleDelete={(selectedIDs) =>
          setEmail({
            ...email,
            sign: email.sign.filter(
              (sign) => !selectedIDs.some((id) => id === sign.id)
            ),
          })
        }
      />

      <Button
        sx={{ display: "flex", margin: "0 auto", my: 4 }}
        onClick={handleUpdate}
        variant="contained"
      >
        Save
      </Button>
    </Box>
  );
}
