package cloudflare

import (
	"bytes"
	"encoding/json"
	"errors"
	"html/template"
	"io"
	"net/http"
	"strings"

	"github.com/pocketbase/pocketbase"
	"github.com/pocketbase/pocketbase/core"
	"github.com/pocketbase/pocketbase/tools/router"
)

var VerifyUrl = "https://challenges.cloudflare.com/turnstile/v0/siteverify"

type TurnstileResponse struct {
	Success     bool     `json:"success"`
	ErrorCodes  []string `json:"error-codes,omitempty"`
	ChallengeTS string   `json:"challenge_ts,omitempty"`
	Hostname    string   `json:"hostname,omitempty"`
}

type TurnStilleCaptcha struct {
	SiteKey   string
	SecretKey string
}

func ServeTurnstilleCaptchaJS(app *pocketbase.PocketBase, se *core.ServeEvent) *router.Route[*core.RequestEvent] {
	return se.Router.GET("/api/email/script.js", func(e *core.RequestEvent) error {
		// www.abrasive.ma-al.pl
		// siteKey:   "0x4AAAAAABdgeAdu4Pxxovj3"
		// secretKey: "0x4AAAAAABdgeHJDjMwmeX5aXaXGh6HWZbw"

		settings, err := GetSettings(app)
		if err != nil {
			return err
		}

		file, err := JS.ReadFile("TurnStilleCaptcha.js")
		if err != nil {
			return err
		}
		templ, err := template.New("test").Parse(string(file))

		buf := bytes.Buffer{}
		templ.Execute(&buf, map[string]interface{}{
			"SiteKey": settings.SiteKey,
		})
		if err != nil {
			return err
		}

		e.Response.Header().Set("Content-Type", "application/javascript")
		return e.String(http.StatusOK, buf.String())
	})
}

func GetSettings(app *pocketbase.PocketBase) (*TurnStilleCaptcha, error) {
	record, err := app.FindFirstRecordByFilter("settings", "key='turnstile'", nil)

	settings := TurnStilleCaptcha{}
	json.Unmarshal([]byte(record.GetString("value")), &settings)

	if err != nil {
		return nil, err
	}

	return &settings, nil
}

func VerifyTurnstile(app *pocketbase.PocketBase, token, ip string) error {
	conf, err := GetSettings(app)
	if err != nil {
		return err
	}

	data := map[string]string{"secret": conf.SecretKey, "response": token, "remoteip": ip}
	jsonData, _ := json.Marshal(data)
	resp, err := http.Post(VerifyUrl, "application/json", bytes.NewBuffer(jsonData))
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	var turnstileResp TurnstileResponse
	body, _ := io.ReadAll(resp.Body)
	json.Unmarshal(body, &turnstileResp)

	if !turnstileResp.Success {
		return errors.New(turnstileResp.ChallengeTS + ": " + strings.Join(turnstileResp.ErrorCodes, " "))
	}
	return nil
}
