import Head from 'next/head'
import Link from 'next/link'
import styles from '/styles/Home.module.css'
import { Service, ServiceStatus, ServiceType, ServiceLocation } from '../interfaces/LinkTypes';
import Dockerode from 'dockerode';
import { ReactElement } from 'react'
import useSWR from 'swr';

const fetcher = (url: string) => fetch(url).then((res) => res.json())

//function Services(props: EntryList) {
function Services() {
  const { initialData, fullData, loadingInitial, loadingFull, error } = useServices();


  let content: ReactElement = <></>;

  if (error) { content = <div>Error loading data</div> }
  else if (loadingInitial) {
    content = <div>Loading</div>
  }
  else if (loadingFull) {
    content =
      <div className={styles.grid}>
        {initialData?.map((item: Service) => (
          <Link key={item.name} href={item.href}>
            <a className={styles.contentcard}>
              <div className={styles.contenttitle}><h2>{item.name}</h2></div>
              <div className={item.status === ServiceStatus.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>
  }
  else if (fullData) {
    content =
      <div className={styles.grid}>
        {fullData.map((item: Service) => (
          <Link key={item.name} href={item.href}>
            <a className={styles.contentcard}>
              <div className={styles.contenttitle}><h2>{item.name}</h2></div>
              <div className={item.status === ServiceStatus.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>
  }
  else {
    content = <div>Error loading data</div>
  }

  return (
    <>
      <Head>
        <title>Neshura Servers</title>
        <meta charSet='utf-8' />
        <link rel="icon" href="/favicon.ico" />
        <meta name="description" content="Lists all available Services, most likely up-to-date" />
      </Head>

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

      <p className={styles.description}>
        Lists all available Services, most likely up-to-date
      </p>

      {content}
    </>
  )
}

async function getStatus(entry: Service, containers: Dockerode.ContainerInfo[]) {
  // Currently the only location supporting different fetching depending on type is brr7-4800u
  // Others to follow but low prio as this is currently the only location used

  // Location BRR7-4800U
  if (entry.location === ServiceLocation.brr7_4800u) {
    // Type APP
    if (entry.type === ServiceType.app) {
      await fetch(entry.href)
        .then((response) => {
          if (response.ok) {
            switch(response.status) {
              case 200:
              case 301:
              case 302:
                entry.status = ServiceStatus.online;
                break;
              default:
                entry.status = ServiceStatus.offline;
            }
          }
          else {
            entry.status = ServiceStatus.offline;
          }
        })
        .catch((error) => {
          console.error("Error pinging Website: ", error);
          entry.status = ServiceStatus.error;
        })
    }
    // Type Docker
    else if (entry.type === ServiceType.docker) {
      containers.forEach((container) => {
        // Docker API returns container names with / prepended
        if (container.Names.includes("/" + entry.docker_container_name)) {
          // so far only "running" is properly implemented, mroe cases to follow as needed
          switch (container.State) {
            case "running":
              entry.status = ServiceStatus.online;
              break;
            default:
              console.log("Container Status " + container.State + " has no case implemented");
              entry.status = ServiceStatus.offline;
          }
        }
        // If container name is not missing the container is set to offline
        else if (entry.docker_container_name !== null) {
          // DEBUG
          console.log(container.Names.includes("/" + entry.docker_container_name))
          console.log("/" + entry.docker_container_name);
          console.log(container.Names[0]);
          // DEBUG
          console.warn("Container for " + entry.name + " could not be found");
          entry.status = ServiceStatus.offline;
        }
        else {
          console.error("Container Name not specified");
          entry.status = ServiceStatus.error;
        }
      })
    }
    // If no Type matches
    else {
      console.warn("Service Type for Service " + entry.name + " not specified or invalid");
      entry.status = ServiceStatus.error;
    }
  }
  // Location Other
  // TODO: implement docker type for other locations
  else if (entry.location === ServiceLocation.other) {
    // Currently uses the same handling as app type for the other location
    await fetch(entry.href)
        .then((response) => {
          if (response.ok) {
            switch(response.status) {
              case 200:
              case 301:
              case 302:
                entry.status = ServiceStatus.online;
                break;
              default:
                entry.status = ServiceStatus.offline;
            }
          }
          else {
            entry.status = ServiceStatus.offline;
          }
        })
        .catch((error) => {
          console.error("Error pinging Website: ", error);
          entry.status = ServiceStatus.error;
        })
  }
  // If no Location matches
  else {
    console.warn("Service Location for Service " + entry.name + " not specified");
    entry.status = ServiceStatus.error;
  }
  return entry;
}

const fetchFullDataArray = (containerData: Dockerode.ContainerInfo[], dataSet: Service[]) => {
  const fetchStatus = (entry: Service) => getStatus(entry, containerData);
  return Promise.all(dataSet.map(fetchStatus));
}

function useServices() {
  const { data: containerData, error: containerError } = useSWR('/api/containers', fetcher);
  const { data: initialData, error: initialError } = useSWR('/api/services', fetcher);
  const loadingInitial = !initialData && !initialError
  const { data: fullData, error: fullError } = useSWR((initialData && containerData) ? [containerData, initialData] : null, fetchFullDataArray)
  const loadingFull = !fullData && !fullError

  console.log(fullError) // DEBUG

  return {
    initialData,
    fullData,
    loadingInitial,
    loadingFull,
    error: initialError || fullError || containerError,
  };
}

export default Services