package main

import (
	"context"
	"crypto/tls"
	"flag"
	"math/rand"
	"net"
	"net/http"
	"time"

	_ "git.xeserv.us/xena/route/internal"
	"git.xeserv.us/xena/route/internal/middleware"
	"git.xeserv.us/xena/route/internal/routecrypto"
	"git.xeserv.us/xena/route/internal/server"
	"github.com/Xe/ln"
	"github.com/caarlos0/env"
	"github.com/facebookgo/flagenv"
	_ "github.com/joho/godotenv/autoload"
)

var (
	sslCertKey = flag.String("ssl-cert-key", "", "if set encrypt SSL certs with this key")
)

func main() {
	flag.Parse()
	flagenv.Parse()
	rand.Seed(time.Now().Unix())
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	certKey, _ := routecrypto.ParseKey(*sslCertKey)

	scfg := server.Config{}
	err := env.Parse(&scfg)
	if err != nil {
		ln.FatalErr(ctx, err, ln.Action("parsing environment for config"))
	}
	scfg.CertKey = certKey

	s, err := server.New(scfg)
	if err != nil {
		ln.FatalErr(ctx, err, ln.Action("create server instance"))
	}

	go setupTLS(s, scfg)

	// listen on HTTP listener
	l, err := net.Listen("tcp", scfg.WebAddr)
	if err != nil {
		ln.FatalErr(ctx, err, ln.Action("listening on HTTP port"), ln.F{"addr": scfg.WebAddr})
	}
	defer l.Close()

	hs := &http.Server{
		Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			switch r.Method {
			case http.MethodPatch, http.MethodPut, http.MethodPost:
				http.Error(w, "use https", http.StatusNotAcceptable)
				ln.Log(r.Context(), ln.Action("cannot redirect (wrong method)"), ln.F{"remote": r.RemoteAddr, "host": r.Host, "path": r.URL.Path})
				return
			}

			r.URL.Host = r.Host
			r.URL.Scheme = "https"

			ln.Log(r.Context(), ln.Action("redirecting insecure HTTP to HTTPS"), ln.F{"remote": r.RemoteAddr, "host": r.Host, "path": r.URL.Path})

			http.Redirect(w, r, r.URL.String(), http.StatusPermanentRedirect)
		}),
		Addr: scfg.WebAddr,
	}

	hs.Serve(l)
}

func setupTLS(s *server.Server, scfg server.Config) {
	hs := &http.Server{
		Handler: middleware.Trace(s),
		Addr:    scfg.SSLAddr,
		TLSConfig: &tls.Config{
			GetCertificate: s.GetCertificate,
		},
	}

	for {
		hs.ListenAndServeTLS("", "")
	}
}
