// pages/index.tsx
import Head from 'next/head';
import { useEffect, useRef, useState } from 'react';

import Box from '../../components/Box';
import TextArea from '../../components/TextArea';
import Input from '../../components/Input';
import Button from '../../components/Button';
import Markdown from '../../components/Markdown';
import Typ from '../../components/Typ';

import PathCrumbs from "../../components/PathCrumbs";

import Script from 'next/script';

// @ts-ignore
import desc from './desc.md';


/*
 * HOOK THE MODULE FROM THE DOM
 */

interface Wg2ndModule {
  wg2nd_cmdseq: (intfName : string, intfconfig : string) => string;
}

declare global {
  interface Window {
    Wg2ndModule: any;
    wg2ndOnLoad: (module : Wg2ndModule) => void
  }
}

const useModule = <T extends any>(onInitCallback? : (module: T) => void): T | null => {
  const [module, setModule] = useState<T | null>(null);

  function setModuleWithCallback(module : T) {
    console.log('setting module');

    if(onInitCallback !== undefined) {
      onInitCallback(module);
    }

    setModule(module);
  }

  useEffect(() => {

    window.wg2ndOnLoad = function() {
      setModuleWithCallback(window.Wg2ndModule);
    }

    if(module === null && typeof window.Wg2ndModule === "object") {
      setModuleWithCallback(window.Wg2ndModule);
    }

  });


  return module;
};


const DEMO_CONFIG = `[Interface]
PrivateKey = 0OCS+dV5wsDje6qUAEDQzPmTNWOLE9HE8kfGU1wJUE0=
Address = 10.55.127.342/32, ab00:aaaa:aaa:aa02::5:abcd/128
DNS = 10.64.0.1

[Peer]
PublicKey = WBSnuq6Vswxz5G5zz9pUt60ZSA+JfZ1iTXdg0RJGjks=
AllowedIPs = 0.0.0.0/0,::0/0
Endpoint = 128.45.210.64:51821
`;

let rows = 0;
for(const char of DEMO_CONFIG)
  if(char == '\n') rows++;

interface PanelProps {
  children?: React.ReactNode;
  customStyle?: React.CSSProperties;
};

const Panel: React.FC<PanelProps> = ({ children, customStyle }) => (
    <section style={{
      backgroundColor: '#f8f9fa',
      marginTop: '1.5rem',
      padding: '1.5rem',
      ...customStyle
    }}>
      {children}
    </section>
);

const Wg2nd = () => {
  const intfNameRef = useRef<HTMLInputElement>(null);
  const intfConfigRef = useRef<HTMLTextAreaElement>(null);
  const ndConfigRef = useRef<HTMLTextAreaElement>(null);
  const parentDebounceDiv = useRef<HTMLDivElement>(null);

  const convertConfig = (module : Wg2ndModule) => {
    if(intfNameRef.current === null || intfConfigRef.current === null
       || ndConfigRef.current === null || parentDebounceDiv.current === null) {
      return;
    }

    const intfName = intfNameRef.current!.value;
    const intfConfig = intfConfigRef.current!.value;

    const result = module.wg2nd_cmdseq(intfName, intfConfig);

    // This is a hack: adjust a wrapper around the output text area
    // Thus, we can detect the scrollHeight of the TextArea without
    // the screen moving.
    parentDebounceDiv.current!.style.height = ndConfigRef.current!.style.height;
    ndConfigRef.current!.style.height = `0px`;

    ndConfigRef.current!.value = result;

    const scrollHeight = ndConfigRef.current!.scrollHeight;
    ndConfigRef.current!.style.height = `${scrollHeight}px`;
    parentDebounceDiv.current!.style.height = 'auto';
  };

  const module = useModule<Wg2ndModule>(convertConfig);

  return (
  <>
    <script src="/wg2nd/wg2nd_bindings.js" />
    <main
        style={{
            maxWidth: '1200px',
            margin: 'auto',
        }}
    >
      {/* Description */}
      <Panel>
        <PathCrumbs path="/wg2nd" />
        <Markdown md={desc} />
      </Panel>

      {/* Input Panel */}
      <Panel>
        <Typ variant="h3">WireGuard Configuration</Typ>
        <Box my={1}>
          <label htmlFor="wg_config_intf_name">
            <Typ variant="h4" gutter>Interface Name</Typ>
          </label>
          <Input
            ref={intfNameRef}
            id="wg_config_intf_name"
            defaultValue="wg0"
            spellCheck={false}
          />
        </Box>
        <Box my={1}>
          <label htmlFor="wg_config_conf">
            <Typ variant="h4" gutter>Interface Configuration</Typ>
          </label>
          <TextArea
            ref={intfConfigRef}
            id="wg_config_conf"
            defaultValue={DEMO_CONFIG}
            rows={rows}
            spellCheck={false}
          />
        </Box>
        <Button
          sx={{width: '100%'}}
          onClick={(e) => {
            if(module !== null) {
              convertConfig(module);
            }
          }}
        >Generate</Button>
      </Panel>

      {/* Output Panel */}
      <Panel>
        <label htmlFor="nd_config_cmds">
          <Typ variant="h3">Networkd Configuration</Typ>
        </label>
        <Box my={1}>
          <div ref={parentDebounceDiv} >
            <TextArea
              sx={{ overflowY: 'hidden' }}
              id="nd_config_cmds"
              ref={ndConfigRef}
              spellCheck={false}
              readOnly
            />
          </div>
        </Box>
      </Panel>
    </main>
  </>
  );
};

export default Wg2nd;
