import Head from 'next/head'
import Link from 'next/link'
import styles from '/styles/Home.module.css'
import fsPromises from 'fs/promises'
import path, { resolve } from 'path'
import type { CustomLink, LinkList } from '../interfaces/LinkTypes'
import Dockerode from 'dockerode';


function Services(props: LinkList) {
  const serviceList = props.services
  return (
    <>
      <Head>
        <title>Neshura Servers</title>
        <meta charSet='utf-8' />
        <link rel="icon" href="/favicon.ico" />
      </Head>

      <h1 className={styles.title}>
        Service List
      </h1>

      <p className={styles.description}>
        Lists all available Services, most likely up-to-date
      </p>
      <div className={styles.grid}>
        {serviceList.map((item: CustomLink) => (
          <Link key={item.name} href={item.href}>
            <a className={styles.contentcard}>
              <div className={styles.contenttitle}><h2>{item.name}</h2></div>
              <div className={item.status == "Online" ? styles.contentonline : styles.contentoffline}>{item.status}</div>
              <div><p>{item.desc}</p></div>
              <div className={styles.cardwarn}><p>{item.warn}</p></div>
            </a>
          </Link>
        ))}
      </div>
    </>
  )
}

// Gets a List of all services specified in /confs/pages.json
export async function getServerSideProps() {
  const filePath = path.join(process.cwd(), './confs/pages.json')
  // TODO: look into asyncing this API call
  const jsonData = await fsPromises.readFile(filePath)
  const list = JSON.parse(jsonData.toString())
  for (let index = 0; index < list.services.length; index++) {
    // TODO: look into asyncing this as well
    await status(list.services[index]);
  }
  return { props: list }
}

// reversing this to loop over given entries for every found container would probably improve latency
async function status(entry: CustomLink) {
  // for now only the BRR7-4800U can be used with Docker, needs changing once more Servers are used
  // TODO: support multiple locations for docker
  if (entry.location === "brr7-4800u") {
    // app in this context means any non-docker page
    if (entry.type === "app") {

      let data = new Response();
      try {
        await fetch(entry.href).then((response: Response) => data = response);
      }
      catch (e) {
        console.log(e)
        return (entry.status = "Offline");
      }

      if (data.ok) {
        if (data.status == 200 || data.status == 301 || data.status == 302) {
          return (entry.status = "Online");
        }
        else return (entry.status = "Offline");
      }
      else return (entry.status = "Offline");
    }
    else if (entry.type === "docker") {
      var Docker = require('dockerode');

      // TODO: read these paths from some config instead of hardcoding them
      const options = {
        socketPath: '/var/run/docker.sock',
        path: '/v1.41/containers/json'
      };
      var docker = new Docker({ socketPath: options.socketPath });

      // default is set as Offline, prevents uncaught cases without set status
      entry.status = "Offline";
      // TODO: async possible?
      await docker.listContainers({all: true}).then(
        ((containers: Dockerode.ContainerInfo[]) => {
          // Loop over every found container and compare to the entry provided
          containers.forEach((element: Dockerode.ContainerInfo) => {
            element.Names.forEach((containerName: string) => {
              if (containerName.startsWith("/")) {
                containerName = containerName.substring(1);
              }
              if (containerName === entry.docker_container_name) {
                entry.status = "Online";
              }
            });
            if (entry.docker_container_name == null) {
              console.log("MISSING DOCKER CONTAINER NAME FOR " + entry.name);
              entry.status = "ERROR";
            }
          });
        })
      );
    }
    else { entry.status = "ERROR" }
    return;
  }
  // for non-local locations pinging can be used to see if they're up
  else if (entry.location != "") {
    let data: Response;
    try {
      data = await fetch(entry.href);
    }
    catch (e) {
      console.log(e)
      return (entry.status = "Offline");
    }

    if (data.ok) {
      if (data.status == 200 || data.status == 301 || data.status == 302) {
        return (entry.status = "Online");
      }
      else return (entry.status = "Offline");
    }
    else return (entry.status = "Offline");
  }
  else { return (entry.status = "ERROR") }
}

export default Services