package main

import (
	"context"
	"crypto/tls"
	"io/ioutil"
	"log"
	"net"
	"os"
	"os/signal"
	"sync"

	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"
	"src.whiteboxsystems.nl/DECOZO/okapi"
	"whiteboxsystems.nl/okapidemo/certgen"
)

var srvaddr = "0.0.0.0:8888"
var patientIf = "0.0.0.0:8085"
var binFolder = "./bin"

func loadCert() *tls.Certificate {
	_, err := os.Stat("certs/client.crt")

	if err != nil {
		_, _, certPem, keyPem, err := certgen.GenCert("whitebox", "whitebox")

		if err != nil {
			panic(err)
		}

		if err != nil {
			panic(err)
		}

		if err := ioutil.WriteFile("certs/client.crt", []byte(certPem), 0600); err != nil {
			panic(err)
		}
		if err := ioutil.WriteFile("certs/client.key", []byte(keyPem), 0600); err != nil {
			panic(err)
		}
	}

	certificate, err := tls.LoadX509KeyPair("certs/client.crt", "certs/client.key")

	if err != nil {
		panic("Load client certification failed: " + err.Error())
	}

	return &certificate
}

func loadKeyPair() credentials.TransportCredentials {
	certificate := loadCert()

	tlsConfig := &tls.Config{
		ClientAuth:   tls.RequestClientCert,
		Certificates: []tls.Certificate{*certificate},
		// ClientCAs:    capool,
	}
	return credentials.NewTLS(tlsConfig)
}

func main() {
	stop := make(chan os.Signal, 1)
	signal.Notify(stop, os.Interrupt)
	wg := &sync.WaitGroup{}

	if os.Getenv("BIN_FOLDER") != "" {
		binFolder = os.Getenv("BIN_FOLDER")
	}

	openapisrv := NewServer()
	openapisrv.LoadData("./data/data.db")
	opts := []grpc.ServerOption{
		grpc.Creds(loadKeyPair()),
	}

	grpcServer := grpc.NewServer(opts...)

	go func() {
		lis, err := net.Listen("tcp", srvaddr)
		if err != nil {
			log.Fatalf("failed to listen: %v", err)
		}

		okapi.RegisterOkAPIServer(grpcServer, openapisrv)
		log.Printf("RPC Listening on %v", srvaddr)
		wg.Add(1)
		grpcServer.Serve(lis)
	}()

	srv := NewUIServer(patientIf)
	srv.data = openapisrv.data

	go func() {
		wg.Add(1)
		srv.ListenAndServe()
	}()

	<-stop

	go func() {
		grpcServer.GracefulStop()
		wg.Done()
		log.Println("Shutdown RPC server")
	}()

	go func() {
		log.Println("Shutdown UI server...")
		srv.Shutdown(context.Background())
		wg.Done()
		log.Println("UI Server shutdown...")
	}()

	wg.Wait()
}
