package main

import (
	"encoding/json"
	"fmt"
	"log/slog"
	"math/rand/v2"
	"net/http"

	"github.com/PuerkitoBio/goquery"
	spinhttp "github.com/fermyon/spin/sdk/go/v2/http"
	"github.com/julienschmidt/httprouter"
)

const (
	contentTypeHeader = "Content-Type"
)

type MonkeyUserEntry struct {
	Title string `json:"title"`
	URL   string `json:"url"`
}

type ImageReference struct {
	URL string `json:"url"`
}

func init() {
	router := spinhttp.NewRouter()

	router.GET("/monkeyuser", monkeyUserComic)

	spinhttp.Handle(router.ServeHTTP)
}

func monkeyUserComic(w http.ResponseWriter, re *http.Request, _ httprouter.Params) {
	indexResponse, err := spinhttp.Get("https://www.monkeyuser.com/index.json")
	if err != nil {
		slog.Error("failed to fetch MonkeyUser index", slog.String("err", err.Error()))
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	slog.Info("Fetched MonkeyUser index")
	defer indexResponse.Body.Close()
	if indexResponse.StatusCode != http.StatusOK {
		w.WriteHeader(indexResponse.StatusCode)
		return
	}

	var entries []MonkeyUserEntry

	if err := json.NewDecoder(indexResponse.Body).Decode(&entries); err != nil {
		slog.Error("failed to decode MonkeyUser index", slog.String("err", err.Error()))
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	slog.Info("Decoded MonkeyUser index")
	entry := entries[rand.IntN(len(entries))]

	pageResponse, err := spinhttp.Get(fmt.Sprintf("https://www.monkeyuser.com%s", entry.URL))
	if err != nil {
		slog.Error("failed to fetch monkeyuser comic page", slog.String("err", err.Error()))
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	defer pageResponse.Body.Close()
	if pageResponse.StatusCode != http.StatusOK {
		w.WriteHeader(pageResponse.StatusCode)
		return
	}

	comicDoc, err := goquery.NewDocumentFromReader(pageResponse.Body)
	if err != nil {
		slog.Error("failed to parse comic page", slog.String("err", err.Error()))
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	var ref ImageReference

	comicDoc.Find("div.content > p > img").Each(func(_ int, s *goquery.Selection) {
		for _, node := range s.Nodes {
			for _, attr := range node.Attr {
				if attr.Key == "src" {
					ref.URL = fmt.Sprintf("https://www.monkeyuser.com%s", attr.Val)
					break
				}
			}
			slog.Info("found URL", slog.String("url", ref.URL))
		}
	})

	w.Header().Add(contentTypeHeader, "application/json")
	w.WriteHeader(http.StatusOK)
	if err := json.NewEncoder(w).Encode(ref); err != nil {
		slog.Error("failed to encode image ref", slog.String("err", err.Error()))
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}