import React, { useEffect, useState } from "react";

import Box from "@mui/material/Box";
import Button from "@mui/material/Button";
import ButtonGroup from "@mui/material/ButtonGroup";
import Collapse from "@mui/material/Collapse";
import IconButton from "@mui/material/IconButton";
import Paper from "@mui/material/Paper";
import Table from "@mui/material/Table";
import TableHead from "@mui/material/TableHead";
import TableRow from "@mui/material/TableRow";
import TableBody from "@mui/material/TableBody";
import TableContainer from "@mui/material/TableContainer";
import TableCell from "@mui/material/TableCell";
import Tooltip from "@mui/material/Tooltip";
import Typography from "@mui/material/Typography";

import { makeStyles } from "tss-react/mui";
import { Theme } from "@mui/material/styles";

import WarningIcon from "@mui/icons-material/Warning";
import DirectionsRunIcon from "@mui/icons-material/DirectionsRun";
import ArrowBackIcon from "@mui/icons-material/ArrowBack";
import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown";
import KeyboardArrowUpIcon from "@mui/icons-material/KeyboardArrowUp";
import ThumbUpAlt from "@mui/icons-material/ThumbUpAlt";
import ThumbDownAlt from "@mui/icons-material/ThumbDownAlt";

import { Skills } from "@nsdefs";

import { ImportData, saveObject } from "../../SaveObject";
import { Settings } from "../../Settings/Settings";
import { convertTimeMsToTimeElapsedString } from "../../utils/StringHelperFunctions";
import { formatMoney, formatNumberNoSuffix } from "../formatNumber";
import { ConfirmationModal } from "./ConfirmationModal";
import { pushImportResult } from "../../Electron";
import { Router } from "../GameRoot";
import { Page } from "../Router";
import { useBoolean } from "./hooks";

import { SaveData } from "../../types";
import { handleGetSaveDataInfoError } from "../../utils/ErrorHandler";
import { OptionSwitch } from "./OptionSwitch";

const ComparisonIcon = ({ isBetter }: { isBetter: boolean }): JSX.Element => {
  const title = isBetter ? "Imported value is larger!" : "Imported value is smaller!";
  const icon = isBetter ? <ThumbUpAlt color="success" /> : <ThumbDownAlt color="error" />;

  return <Tooltip title={title}>{icon}</Tooltip>;
};

const useStyles = makeStyles()((theme: Theme) => ({
  root: {
    padding: theme.spacing(2),
    maxWidth: "1000px",

    "& .MuiTable-root": {
      "& .MuiTableCell-root": {
        borderBottom: `1px solid ${Settings.theme.welllight}`,
        width: "30%",
      },
      "& .MuiTableCell-root:last-child": {
        width: "10%",
      },

      "& .MuiTableHead-root .MuiTableRow-root": {
        backgroundColor: Settings.theme.backgroundsecondary,

        "& .MuiTableCell-root": {
          color: Settings.theme.primary,
          fontWeight: "bold",
        },
      },

      "& .MuiTableBody-root": {
        "& .MuiTableRow-root:nth-of-type(odd)": {
          backgroundColor: Settings.theme.well,

          "& .MuiTableCell-root": {
            color: Settings.theme.primarylight,
          },
        },
        "& .MuiTableRow-root:nth-of-type(even)": {
          backgroundColor: Settings.theme.backgroundsecondary,

          "& .MuiTableCell-root": {
            color: Settings.theme.primarylight,
          },
        },
      },
    },
  },

  skillTitle: {
    textTransform: "capitalize",
  },
}));

// TODO: move to game constants and/or extract as an enum
const playerSkills: (keyof Skills)[] = ["hacking", "strength", "defense", "dexterity", "agility", "charisma"];

let initialAutosave = 0;

export const ImportSaveComparison = (props: { saveData: SaveData; automatic: boolean }): JSX.Element => {
  const { classes } = useStyles();
  const [importData, setImportData] = useState<ImportData | undefined>();
  const [currentData, setCurrentData] = useState<ImportData | undefined>();
  const [isImportModalOpen, { on: openImportModal, off: closeImportModal }] = useBoolean(false);
  const [isSkillsExpanded, { toggle: toggleSkillsExpand }] = useBoolean(true);
  const [isOthersExpanded, { toggle: toggleOthersExpand }] = useBoolean(true);
  const [headBack, setHeadBack] = useState(false);
  const [syncSteamAchievements, setSyncSteamAchievements] = useState(true);

  const handleGoBack = (): void => {
    Settings.AutosaveInterval = initialAutosave;
    pushImportResult(false);
    Router.allowRouting(true);
    setHeadBack(true);
  };

  const handleImport = async (): Promise<void> => {
    let overrideSettings = undefined;
    if (syncSteamAchievements !== importData?.playerData?.syncSteamAchievements) {
      overrideSettings = {
        SyncSteamAchievements: syncSteamAchievements,
      };
    }
    await saveObject.importGame(props.saveData, overrideSettings);
  };

  useEffect(() => {
    // We want to disable autosave while we're in this mode
    initialAutosave = Settings.AutosaveInterval;
    Settings.AutosaveInterval = 0;
    Router.allowRouting(false);
  }, []);

  useEffect(() => {
    if (headBack) {
      Router.toPage(Page.Terminal);
    }
  }, [headBack]);

  useEffect(() => {
    async function fetchData(): Promise<void> {
      const dataBeingImported = await saveObject.getImportDataFromSaveData(props.saveData);
      const dataCurrentlyInGame = await saveObject.getImportDataFromSaveData(await saveObject.getSaveData(true));

      setImportData(dataBeingImported);
      setCurrentData(dataCurrentlyInGame);
      setSyncSteamAchievements(dataBeingImported.playerData?.syncSteamAchievements ?? true);
    }
    if (props.saveData) {
      fetchData().catch((error) => {
        handleGoBack();
        // We cannot show dialog box in this screen (due to "withPopups = false"), so we will try showing it with a
        // delay. 1 second is usually enough to go back to other normal screens that allow showing popups.
        setTimeout(() => {
          handleGetSaveDataInfoError(error);
        }, 1000);
      });
    }
  }, [props.saveData]);

  if (!importData || !currentData) return <></>;

  return (
    <Box className={classes.root}>
      <Typography variant="h4" sx={{ mb: 2 }}>
        Import Save Comparison
      </Typography>
      {props.automatic && (
        <Typography sx={{ mb: 2 }}>
          We've found a <b>NEWER save</b> that you may want to use instead.
        </Typography>
      )}
      <Typography variant="body1" sx={{ mb: 2 }}>
        Your current game's data is on the left and the data that will be imported is on the right.
        <br />
        Please double check everything is fine before proceeding!
      </Typography>
      <TableContainer color="secondary" component={Paper}>
        <Table>
          <TableHead>
            <TableRow>
              <TableCell></TableCell>
              <TableCell>Current Game</TableCell>
              <TableCell>Being Imported</TableCell>
              <TableCell></TableCell>
            </TableRow>
          </TableHead>

          <TableBody>
            <TableRow>
              <TableCell>Game Identifier</TableCell>
              <TableCell>{currentData.playerData?.identifier ?? "n/a"}</TableCell>
              <TableCell>{importData.playerData?.identifier ?? "n/a"}</TableCell>
              <TableCell>
                {importData.playerData?.identifier !== currentData.playerData?.identifier && (
                  <Tooltip title="These are two different games!">
                    <WarningIcon color="warning" />
                  </Tooltip>
                )}
              </TableCell>
            </TableRow>
            <TableRow>
              <TableCell>Playtime</TableCell>
              <TableCell>{convertTimeMsToTimeElapsedString(currentData.playerData?.totalPlaytime ?? 0)}</TableCell>
              <TableCell>{convertTimeMsToTimeElapsedString(importData.playerData?.totalPlaytime ?? 0)}</TableCell>
              <TableCell>
                {importData.playerData?.totalPlaytime !== currentData.playerData?.totalPlaytime && (
                  <ComparisonIcon
                    isBetter={
                      (importData.playerData?.totalPlaytime ?? 0) > (currentData.playerData?.totalPlaytime ?? 0)
                    }
                  />
                )}
              </TableCell>
            </TableRow>

            <TableRow>
              <TableCell>Saved On</TableCell>
              <TableCell>
                {(currentData.playerData?.lastSave ?? 0) > 0
                  ? new Date(currentData.playerData?.lastSave ?? 0).toLocaleString()
                  : "n/a"}
              </TableCell>
              <TableCell>
                {(importData.playerData?.lastSave ?? 0) > 0
                  ? new Date(importData.playerData?.lastSave ?? 0).toLocaleString()
                  : "n/a"}
              </TableCell>
              <TableCell>
                {importData.playerData?.lastSave !== currentData.playerData?.lastSave && (
                  <ComparisonIcon
                    isBetter={(importData.playerData?.lastSave ?? 0) > (currentData.playerData?.lastSave ?? 0)}
                  />
                )}
              </TableCell>
            </TableRow>

            <TableRow>
              <TableCell>Money</TableCell>
              <TableCell>{formatMoney(currentData.playerData?.money ?? 0)}</TableCell>
              <TableCell>{formatMoney(importData.playerData?.money ?? 0)}</TableCell>
              <TableCell>
                {importData.playerData?.money !== currentData.playerData?.money && (
                  <ComparisonIcon
                    isBetter={(importData.playerData?.money ?? 0) > (currentData.playerData?.money ?? 0)}
                  />
                )}
              </TableCell>
            </TableRow>

            <TableRow>
              <TableCell colSpan={4}>
                <IconButton aria-label="expand row" size="small" onClick={toggleSkillsExpand}>
                  {isSkillsExpanded ? <KeyboardArrowUpIcon /> : <KeyboardArrowDownIcon />}
                </IconButton>
                Skills
              </TableCell>
            </TableRow>
            <TableRow>
              <TableCell colSpan={4} padding="none">
                <Collapse in={isSkillsExpanded}>
                  <Table>
                    <TableBody>
                      <TableRow>{/* empty row to keep even/odd coloring */}</TableRow>
                      {playerSkills.map((skill) => {
                        const currentSkill = currentData.playerData?.skills[skill] ?? 0;
                        const importSkill = importData.playerData?.skills[skill] ?? 0;
                        return (
                          <TableRow key={skill}>
                            <TableCell className={classes.skillTitle}>{skill}</TableCell>
                            <TableCell>{formatNumberNoSuffix(currentSkill, 0)}</TableCell>
                            <TableCell>{formatNumberNoSuffix(importSkill, 0)}</TableCell>
                            <TableCell>
                              {currentSkill !== importSkill && <ComparisonIcon isBetter={importSkill > currentSkill} />}
                            </TableCell>
                          </TableRow>
                        );
                      })}
                      {playerSkills.length % 2 === 1 && (
                        <TableRow>{/* empty row to keep even/odd coloring */}</TableRow>
                      )}
                    </TableBody>
                  </Table>
                </Collapse>
              </TableCell>
            </TableRow>
            <TableRow>{/* empty row to keep even/odd coloring */}</TableRow>

            <TableRow>
              <TableCell colSpan={4}>
                <IconButton aria-label="expand row" size="small" onClick={toggleOthersExpand}>
                  {isOthersExpanded ? <KeyboardArrowUpIcon /> : <KeyboardArrowDownIcon />}
                </IconButton>
                Others
              </TableCell>
            </TableRow>
            <TableRow>
              <TableCell colSpan={4} padding="none">
                <Collapse in={isOthersExpanded}>
                  <Table>
                    <TableBody>
                      <TableRow>
                        <TableCell>Augmentations</TableCell>
                        <TableCell>{currentData.playerData?.augmentations}</TableCell>
                        <TableCell>{importData.playerData?.augmentations}</TableCell>
                        <TableCell>
                          {importData.playerData?.augmentations !== currentData.playerData?.augmentations && (
                            <ComparisonIcon
                              isBetter={
                                (importData.playerData?.augmentations ?? 0) >
                                (currentData.playerData?.augmentations ?? 0)
                              }
                            />
                          )}
                        </TableCell>
                      </TableRow>

                      <TableRow>
                        <TableCell>Factions</TableCell>
                        <TableCell>{currentData.playerData?.factions}</TableCell>
                        <TableCell>{importData.playerData?.factions}</TableCell>
                        <TableCell>
                          {importData.playerData?.factions !== currentData.playerData?.factions && (
                            <ComparisonIcon
                              isBetter={
                                (importData.playerData?.factions ?? 0) > (currentData.playerData?.factions ?? 0)
                              }
                            />
                          )}
                        </TableCell>
                      </TableRow>
                      <TableRow>
                        <TableCell>Achievements</TableCell>
                        <TableCell>{currentData.playerData?.achievements}</TableCell>
                        <TableCell>{importData.playerData?.achievements}</TableCell>
                        <TableCell>
                          {importData.playerData?.achievements !== currentData.playerData?.achievements && (
                            <ComparisonIcon
                              isBetter={
                                (importData.playerData?.achievements ?? 0) > (currentData.playerData?.achievements ?? 0)
                              }
                            />
                          )}
                        </TableCell>
                      </TableRow>

                      <TableRow>
                        <Tooltip title="The total SF levels owned, except for SF-1 Exploit levels.">
                          <TableCell>Source File Levels</TableCell>
                        </Tooltip>
                        <TableCell>{currentData.playerData?.sourceFiles}</TableCell>
                        <TableCell>{importData.playerData?.sourceFiles}</TableCell>
                        <TableCell>
                          {importData.playerData?.sourceFiles !== currentData.playerData?.sourceFiles && (
                            <ComparisonIcon
                              isBetter={
                                (importData.playerData?.sourceFiles ?? 0) > (currentData.playerData?.sourceFiles ?? 0)
                              }
                            />
                          )}
                        </TableCell>
                      </TableRow>

                      <TableRow>
                        <Tooltip title="Number of exploits owned.">
                          <TableCell>Exploits</TableCell>
                        </Tooltip>
                        <TableCell>{currentData.playerData?.exploits}</TableCell>
                        <TableCell>{importData.playerData?.exploits}</TableCell>
                        <TableCell>
                          {importData.playerData?.exploits !== currentData.playerData?.exploits && (
                            <ComparisonIcon
                              isBetter={
                                (importData.playerData?.exploits ?? 0) > (currentData.playerData?.exploits ?? 0)
                              }
                            />
                          )}
                        </TableCell>
                      </TableRow>

                      <TableRow>
                        <Tooltip title="The player's current BitNode.">
                          <TableCell>BitNode</TableCell>
                        </Tooltip>
                        <TableCell>
                          {currentData.playerData?.bitNode}-{currentData.playerData?.bitNodeLevel}
                        </TableCell>
                        <TableCell>
                          {importData.playerData?.bitNode}-{importData.playerData?.bitNodeLevel}
                        </TableCell>
                        <TableCell></TableCell>
                      </TableRow>
                    </TableBody>
                  </Table>
                </Collapse>
              </TableCell>
            </TableRow>
          </TableBody>
        </Table>
      </TableContainer>

      <br />
      <OptionSwitch
        checked={syncSteamAchievements}
        onChange={(newValue) => setSyncSteamAchievements(newValue)}
        text="Sync Steam achievements"
        tooltip={
          <>
            This setting is only used in the Steam app. If this setting is enabled, the game will automatically sync
            your unlocked Steam achievements to Steam Cloud.
          </>
        }
      />

      <Box sx={{ display: "flex", justifyContent: "flex-end" }}>
        <ButtonGroup>
          <Tooltip title="Continue with current save">
            <Button onClick={handleGoBack} sx={{ my: 2 }} startIcon={<ArrowBackIcon />} color="secondary">
              Take me back!
            </Button>
          </Tooltip>
          <Tooltip title="Import newer save and reload">
            <Button onClick={openImportModal} sx={{ my: 2 }} startIcon={<DirectionsRunIcon />} color="warning">
              Proceed with import
            </Button>
          </Tooltip>
        </ButtonGroup>
        <ConfirmationModal
          open={isImportModalOpen}
          onClose={closeImportModal}
          onConfirm={() => {
            handleImport().catch((error) => {
              console.error(error);
            });
          }}
          confirmationText={
            <>
              Importing new save game data will <strong>completely wipe</strong> the current game data!
              <br />
            </>
          }
          additionalButton={<Button onClick={closeImportModal}>Cancel</Button>}
        />
      </Box>
    </Box>
  );
};
