import React, { useEffect, useState } from "react";
import { useHistory, useParams } from "react-router";
import { useSelector, useDispatch } from "react-redux";

import * as fs from "fs";
import * as path from "path";
import { checkWgIsInstalled, WgConfig } from "wireguard-tools";

import { Button, Flex, Input, Text, Textarea } from "@chakra-ui/react";
import { DeleteIcon } from "@chakra-ui/icons";
import { toast } from "react-toastify";

import * as WireGuard from "../utils/wg";
import {
  addFile,
  deleteFile,
  fetchFiles,
  updateStatus,
} from "../store/modules/wgConfig/action";

import {
  AppState,
  StoreState,
  WgConfigFile,
  WgConfigState,
} from "../types/store";

import { DialogButton } from "../components/Dialog";
import Content from "../components/Content";

interface TunnelParam {
  name: string;
}

export default function TunnelInfo() {
  const history = useHistory();
  const dispatch = useDispatch();
  const [wgConfigFile, setWgConfigFile] = useState<WgConfigFile>();
  const [fileName, setFileName] = useState<string>("");
  const [interfaceText, setInterfaceText] = useState<string>("");
  const [originalInterfaceText, setOriginalInterfaceText] = useState<string>(
    ""
  );
  const { name } = useParams<TunnelParam>();
  const { files } = useSelector<StoreState, WgConfigState>(
    (state) => state.wgConfig
  );
  const { userDataPath } = useSelector<StoreState, AppState>(
    (state) => state.app
  );

  useEffect(() => {
    const filePath = path.join(userDataPath, "configurations", `${name}.conf`);

    const data = fs.readFileSync(filePath, "utf-8");
    const config = new WgConfig({});
    config.parse(data);

    setFileName(name);
    setInterfaceText(config.toString());
    setOriginalInterfaceText(config.toString());
    setWgConfigFile(files.find((f) => f.name === name));
  }, [name]);

  useEffect(() => {
    setWgConfigFile(files.find((f) => f.name === name));
  }, [files]);

  async function toggleActive() {
    if (!wgConfigFile) {
      toast("Could not load config file", { type: "error" });
      return;
    }

    try {
      const started = await WireGuard.toggle(wgConfigFile.path);
      const message = started ? "Activated" : "Deactivated";
      toast(`${message} ${wgConfigFile.name}`, { type: "success" });
      dispatch(updateStatus(started ? wgConfigFile.name : ""));
    } catch (e) {
      try {
        await checkWgIsInstalled();
      } catch (e) {
        toast("Wireguard was not detected on the system. If you just installed it, try restarting wiregui.", { type: "error" });
        return;
      }
      toast(e.message, { type: "error" });
    }
  }

  async function handleDelete() {
    if (!wgConfigFile) {
      toast(`Could not find config for ${name}`, { type: "error" });
      return;
    }

    if (wgConfigFile.active) {
      toast("Stop the tunnel before deleting", { type: "error" });
      return;
    }

    try {
      dispatch(deleteFile(wgConfigFile, userDataPath));
      history.push("/");
    } catch (e) {
      toast(e.message, { type: "error" });
    }
  }

  async function handleSave(): Promise<void> {
    if (files.some((f) => f.name === fileName && fileName !== name)) {
      toast(`A tunnel named ${fileName} already exists`, { type: "error" });
      return;
    }

    if (fileName.length > 15) {
      toast("Filename is too long, maximum 15 characters", { type: "error" });
      return;
    }

    try {
      if (wgConfigFile) {
        if (wgConfigFile.active) {
          toast("Stop the tunnel before updating", { type: "error" });
          return;
        }
        dispatch(deleteFile(wgConfigFile, userDataPath));
      }
      dispatch(addFile(`${fileName}.conf`, interfaceText, userDataPath));

      if (fileName !== name) {
        const lastConnectAt = localStorage.getItem(name);
        if (lastConnectAt) {
          localStorage.setItem(fileName, lastConnectAt);
          localStorage.removeItem(name);
        }
        history.push(`/tunnel/${fileName}`);
      }

      setOriginalInterfaceText(interfaceText);
      dispatch(fetchFiles(userDataPath));
    } catch (e) {
      toast(e.message, { type: "error" });
    }
  }

  function isAllowedToSave(): boolean {
    return (
      (fileName !== name || interfaceText !== originalInterfaceText) &&
      fileName.length > 0 &&
      interfaceText.length > 0
    );
  }

  function onNameChange(event: React.ChangeEvent<HTMLInputElement>): void {
    setFileName(event.target.value);
  }

  function onInterfaceTextChange(
    event: React.ChangeEvent<HTMLTextAreaElement>
  ): void {
    setInterfaceText(event.target.value);
  }

  function handleCancel() {
    history.push("/");
  }

  return (
    <Content>
      <Flex
        bg="gray.200"
        borderRadius="4"
        color="whiteAlpha.700"
        direction="column"
        p="4"
        w="575px"
        h="auto"
        mx="auto"
        my="10"
      >
        <Flex justify="space-between" w="100%">
          <Text color="whiteAlpha.800" fontSize="lg" fontWeight="bold">
            {name}
          </Text>
          <DialogButton
            title="Delete"
            color="whiteAlpha.800"
            colorScheme="red"
            header="Are you sure?"
            body="You cannot recover this file after deleting."
            onConfirm={handleDelete}
            launchButtonText={<DeleteIcon />}
          />
        </Flex>
        <Flex align="center" mt="4" w="100%">
          <Text>Name:</Text>
          <Input
            bg="gray.300"
            borderColor="transparent"
            size="xs"
            w="50%"
            ml="2"
            value={fileName}
            onChange={onNameChange}
          />
        </Flex>
        <Flex direction="column" mt="4" w="100%" h="100%">
          <Text fontWeight="medium">Interface:&nbsp;</Text>
          <Textarea
            bg="gray.300"
            borderColor="transparent"
            size="xs"
            resize="none"
            mt="2"
            w="100%"
            h="100%"
            value={interfaceText}
            onChange={onInterfaceTextChange}
          />
        </Flex>
        <Flex justify="flex-end" mt="4">
          <Button size="sm" onClick={handleCancel}>
            Cancel
          </Button>
          <Button colorScheme="orange" color="whiteAlpha.800" size="sm" ml="4" onClick={toggleActive}>
            {wgConfigFile && wgConfigFile.active ? "Deactivate" : "Activate"}
          </Button>
          {isAllowedToSave() && (
            <Button colorScheme="green" color="blackAlpha.800" size="sm" ml="4" onClick={handleSave}>
              Save
            </Button>
          )}
        </Flex>
      </Flex>
    </Content>
  );
}