package webserver

import (
	"bytes"
	"strings"
	"time"

	"encoding/json"
	"net/http"
	"text/template"

	"istheinternetonfire.app/assets"
	"istheinternetonfire.app/internal/cisa"
	"istheinternetonfire.app/internal/config"
)

const (
	ERR_PARSE_TEMPLATE = "Template Parse Error"
	ERR_EXEC_TEMPLATE  = "Template Execution Error"
)

type webErrStruct struct {
	Error    bool   `json:"error"         yaml:"error"`
	ErrorMsg string `json:"error_message" yaml:"errorMessage"`
}

func tmpltError(w http.ResponseWriter, serverStatus int, message string) {
	var (
		output []byte
		o      = webErrStruct{
			Error:    true,
			ErrorMsg: message,
		}
		err error
	)

	w.Header().Add("Content-Type", "application/json")
	output, err = json.MarshalIndent(o, "", "  ")
	if err != nil {
		config.Cfg.Log.Warn("marshal error", "error", err)
		w.WriteHeader(serverStatus)
		w.Write(output) //nolint:errcheck
	}
}

func tmpltWebRoot(w http.ResponseWriter, r *http.Request) {
	tmplt, err := template.New("index.tplt").Funcs(template.FuncMap{
		"ToUpper": strings.ToUpper,
	}).ParseFS(
		assets.EmbedHTML,
		"html/index.tplt",
		"html/css/style.css",
	)
	if err != nil {
		config.Cfg.Log.Debug(ERR_PARSE_TEMPLATE, "error", err)
		tmpltError(w, http.StatusInternalServerError, ERR_PARSE_TEMPLATE)
		return
	}

	msgBuffer, err := processCVEData(tmplt, w)
	if err != nil {
		return
	}

	w.Write(msgBuffer.Bytes()) //nolint:errcheck
}

func tmpltStatusNotFound(w http.ResponseWriter, path string) {
	tmplt, err := template.ParseFS(assets.EmbedHTML, "html/file-not-found.tplt")
	if err != nil {
		config.Cfg.Log.Debug(ERR_PARSE_TEMPLATE, "error", err)
		tmpltError(w, http.StatusInternalServerError, ERR_PARSE_TEMPLATE)
		return
	}

	var msgBuffer bytes.Buffer
	if err := tmplt.Execute(&msgBuffer, struct {
		Title     string
		ErrorCode int
	}{
		Title:     path,
		ErrorCode: http.StatusNotFound,
	}); err != nil {
		config.Cfg.Log.Debug(ERR_EXEC_TEMPLATE, "error", err)
		tmpltError(w, http.StatusInternalServerError, ERR_PARSE_TEMPLATE)
		return
	}
	w.Write(msgBuffer.Bytes()) //nolint:errcheck
}

func tmpltTXT(w http.ResponseWriter) {
	tmplt, err := template.New("site.txt.tplt").Funcs(template.FuncMap{
		"ToUpper": strings.ToUpper,
	}).ParseFS(
		assets.EmbedHTML,
		"html/site.txt.tplt",
	)
	if err != nil {
		config.Cfg.Log.Debug(ERR_PARSE_TEMPLATE, "error", err)
		tmpltError(w, http.StatusInternalServerError, ERR_PARSE_TEMPLATE)
		return
	}

	msgBuffer, err := processCVEData(tmplt, w)
	if err != nil {
		return
	}

	w.Header().Add("Content-Type", TYPE_TEXT_PLAIN)
	w.Write(msgBuffer.Bytes()) //nolint:errcheck
}

func processCVEData(tmplt *template.Template, w http.ResponseWriter) (bytes.Buffer, error) {
	var (
		msgBuffer bytes.Buffer
		cves      []cisa.VulStruct
		num       int = 3
	)

	c := cisa.Read()
	for _, i := range c.Vulnerabilities {
		t, _ := time.Parse("2006-01-02", i.DateAdded)
		if t.After(time.Now().Add(-time.Hour * 720)) {
			cves = append(cves, i)
		}
	}

	if len(cves) < 3 {
		num = len(cves)
	}

	if err := tmplt.Execute(&msgBuffer, struct {
		CVEs []cisa.VulStruct
	}{
		CVEs: cves[len(cves)-num:],
	}); err != nil {
		config.Cfg.Log.Debug(ERR_EXEC_TEMPLATE, "error", err)
		tmpltError(w, http.StatusInternalServerError, ERR_PARSE_TEMPLATE)
		return msgBuffer, err
	}

	return msgBuffer, nil
}