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"
	"src.whiteboxsystems.nl/DECOZO/okapidemo/certgen"
)

var rpcPort = "9999"
var rpcAddr = "0.0.0.0:" + rpcPort
var extRpcAddr = "localhost:" + rpcPort
var uiAddr = "0.0.0.0:9095"

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

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

		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()

	// data, err := ioutil.ReadFile("certs/ca.crt")
	// if err != nil {
	// 	panic("failed to load CA file: " + err.Error())
	// }

	// capool := x509.NewCertPool()
	// if !capool.AppendCertsFromPEM(data) {
	// 	panic("can't add ca cert")
	// }

	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{}

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

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

	if ext := os.Getenv("EXT_ADDR"); ext != "" {
		extRpcAddr = ext + ":" + rpcPort
	}

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

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

	srv := NewUIServer(uiAddr)
	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()
}
