package main

import (
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"path/filepath"

	"imuslab.com/arozos/ReverseProxy/mod/utils"
)

//Check if the default certificates is correctly setup
func handleDefaultCertCheck(w http.ResponseWriter, r *http.Request) {
	type CheckResult struct {
		DefaultPubExists bool
		DefaultPriExists bool
	}

	pub, pri := tlsCertManager.DefaultCertExistsSep()
	js, _ := json.Marshal(CheckResult{
		pub,
		pri,
	})

	sendJSONResponse(w, string(js))
}

//Return a list of domains where the certificates covers
func handleListCertificate(w http.ResponseWriter, r *http.Request) {
	filenames, err := tlsCertManager.ListCertDomains()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	showDate, _ := utils.GetPara(r, "date")
	if showDate == "true" {
		type CertInfo struct {
			Domain           string
			LastModifiedDate string
		}

		results := []*CertInfo{}

		for _, filename := range filenames {
			fileInfo, err := os.Stat(filepath.Join(tlsCertManager.CertStore, filename+".crt"))
			if err != nil {
				sendErrorResponse(w, "invalid domain certificate discovered: "+filename)
				return
			}
			modifiedTime := fileInfo.ModTime().Format("2006-01-02 15:04:05")

			thisCertInfo := CertInfo{
				Domain:           filename,
				LastModifiedDate: modifiedTime,
			}

			results = append(results, &thisCertInfo)
		}

		js, _ := json.Marshal(results)
		w.Header().Set("Content-Type", "application/json")
		w.Write(js)
	} else {
		response, err := json.Marshal(filenames)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		w.Header().Set("Content-Type", "application/json")
		w.Write(response)
	}

}

//Handle front-end toggling TLS mode
func handleToggleTLSProxy(w http.ResponseWriter, r *http.Request) {
	currentTlsSetting := false
	if sysdb.KeyExists("settings", "usetls") {
		sysdb.Read("settings", "usetls", &currentTlsSetting)
	}

	newState, err := utils.PostPara(r, "set")
	if err != nil {
		//No setting. Get the current status
		js, _ := json.Marshal(currentTlsSetting)
		utils.SendJSONResponse(w, string(js))
	} else {
		if newState == "true" {
			sysdb.Write("settings", "usetls", true)
			log.Println("Enabling TLS mode on reverse proxy")
			dynamicProxyRouter.UpdateTLSSetting(true)
		} else if newState == "false" {
			sysdb.Write("settings", "usetls", false)
			log.Println("Disabling TLS mode on reverse proxy")
			dynamicProxyRouter.UpdateTLSSetting(false)
		} else {
			utils.SendErrorResponse(w, "invalid state given. Only support true or false")
			return
		}

		sendOK(w)

	}
}

//Handle upload of the certificate
func handleCertUpload(w http.ResponseWriter, r *http.Request) {
	// check if request method is POST
	if r.Method != "POST" {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	// get the key type
	keytype, err := utils.GetPara(r, "ktype")
	overWriteFilename := ""
	if err != nil {
		http.Error(w, "Not defined key type (pub / pri)", http.StatusBadRequest)
		return
	}

	// get the domain
	domain, err := utils.GetPara(r, "domain")
	if err != nil {
		//Assume localhost
		domain = "default"
	}

	if keytype == "pub" {
		overWriteFilename = domain + ".crt"
	} else if keytype == "pri" {
		overWriteFilename = domain + ".key"
	} else {
		http.Error(w, "Not supported keytype: "+keytype, http.StatusBadRequest)
		return
	}

	// parse multipart form data
	err = r.ParseMultipartForm(10 << 20) // 10 MB
	if err != nil {
		http.Error(w, "Failed to parse form data", http.StatusBadRequest)
		return
	}

	// get file from form data
	file, _, err := r.FormFile("file")
	if err != nil {
		http.Error(w, "Failed to get file", http.StatusBadRequest)
		return
	}
	defer file.Close()

	// create file in upload directory
	os.MkdirAll("./certs", 0775)
	f, err := os.Create(filepath.Join("./certs", overWriteFilename))
	if err != nil {
		http.Error(w, "Failed to create file", http.StatusInternalServerError)
		return
	}
	defer f.Close()

	// copy file contents to destination file
	_, err = io.Copy(f, file)
	if err != nil {
		http.Error(w, "Failed to save file", http.StatusInternalServerError)
		return
	}

	// send response
	fmt.Fprintln(w, "File upload successful!")
}

//Handle cert remove
func handleCertRemove(w http.ResponseWriter, r *http.Request) {
	domain, err := utils.PostPara(r, "domain")
	if err != nil {
		sendErrorResponse(w, "invalid domain given")
		return
	}
	err = tlsCertManager.RemoveCert(domain)
	if err != nil {
		sendErrorResponse(w, err.Error())
	}
}
