package main

import (
	"context"
	"fmt"
	"io"
	"net"
	"net/url"
	"strings"

	"github.com/fastly/compute-sdk-go/fsthttp"
	"github.com/valyala/fastjson"
)

type Outcome int
const (
	MissingQueryString Outcome = iota
	InvalidQueryString
	GoogleDnsFailed
	IsGoogleBot
	NotGoogleBot
	NoPtrAnser
)
const Backend = "origin_0"

func (o Outcome) Into(w fsthttp.ResponseWriter, ptr string) fsthttp.ResponseWriter {
	var result string
	var reason string
	var status int
	switch o {
	case MissingQueryString:
		result = "error"
		reason = "Missing query string ?ip=a.b.c.d"
		status = fsthttp.StatusBadRequest
	case InvalidQueryString:
		result = "error"
		reason = "Invalid query string ?ip=a.b.c.d"
		status = fsthttp.StatusBadRequest
	case GoogleDnsFailed:
		result = "error"
		reason = "Google DNS failed\n" + ptr
		status = fsthttp.StatusBadGateway
	case IsGoogleBot:
		result = "yes"
		reason = "Reverse lookup is " + ptr
		status = fsthttp.StatusOK
	case NotGoogleBot:
		result = "no"
		reason = "Reverse lookup is " + ptr + ", not an *.google.com or *.googlebot.com domain."
		status = fsthttp.StatusOK
	case NoPtrAnser:
		result = "no"
		reason = "No PTR Answer for this reverse lookup."
		status = fsthttp.StatusOK
	}
	w.Header().Set("x-googlebot-verified", result)
    w.Header().Set("x-googlebot-verified-reason", reason)
	w.WriteHeader(status)
	fmt.Fprintf(w, `{"result": "%s", "reason": "%s"}\n`, result, reason)
	return w
}

func main() {
	fsthttp.ServeFunc(func(ctx context.Context, w fsthttp.ResponseWriter, r *fsthttp.Request) {
		if r.URL.Path == "/verify" && r.Method == "GET" {
			w = handle_lookup_request(ctx, w, *r)
			return
		}

		// Catch all other requests and return a 404.
		w.WriteHeader(fsthttp.StatusNotFound)
		fmt.Fprintf(w, "The page you requested could not be found\n")
	})
}

func handle_lookup_request(ctx context.Context, w fsthttp.ResponseWriter, req fsthttp.Request) fsthttp.ResponseWriter {
	var qs_params = req.URL.RawQuery
	if qs_params == "" {
		return MissingQueryString.Into(w, "")
	}
	qs_map, err := url.ParseQuery(qs_params)
	if err != nil {
		fmt.Print(err)
		return MissingQueryString.Into(w, "")
	}
	ipaddrStr := strings.Join(qs_map["ip"], "")
	if ipaddrStr == "" {
		return InvalidQueryString.Into(w, "")
	}
	ipaddr := net.ParseIP(ipaddrStr)
	if ipaddr == nil {
		return InvalidQueryString.Into(w, "")
	}
	ipaddr_slice := strings.Split(ipaddrStr, ".")
	req.URL, err = url.Parse("https://dns.google.com/resolve?name=" + ipaddr_slice[3] + "." + ipaddr_slice[2] + "." + ipaddr_slice[1] + "." + ipaddr_slice[0] + ".in-addr.arpa&type=PTR")
	if err != nil {
		fmt.Print("URL: ", err)
	}
  //deleting accept-encoding to prevent a compressed content from a backend. This is only for fiddle.
  req.Header.Del("accept-encoding")
	resp, err := req.Send(ctx, Backend)
	if err != nil {
		fmt.Print(err)
		return GoogleDnsFailed.Into(w, "Send error: " + err.Error())
	}
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		fmt.Print(err)
		return GoogleDnsFailed.Into(w, "Read error: " + err.Error())
	}
	fmt.Println("Body String: ", string(body))
	var p fastjson.Parser
	body_json, err := p.ParseBytes(body)
	if err != nil {
		fmt.Print(err)
		return GoogleDnsFailed.Into(w, "Parse error:" + err.Error())
	}
	ptr_record := body_json.Get("Answer", "0", "data").GetStringBytes()
	if ptr_record == nil {
		return NoPtrAnser.Into(w, "")
	}
	if strings.HasSuffix(string(ptr_record), ".google.com.") || strings.HasSuffix(string(ptr_record), ".googlebot.com.") {
		return IsGoogleBot.Into(w, string(ptr_record))
	}

	return NotGoogleBot.Into(w, string(ptr_record))

}