package server

import (
	"bytes"
	"fmt"
	"image"
	"image/color"
	"image/draw"
	"image/png"
	"io"
	"net/http"
	"strings"

	"github.com/golang/freetype"
	"github.com/golang/freetype/truetype"
	"github.com/kataras/iris/v12"
	"github.com/rs/zerolog/log"
	"golang.org/x/image/font"
	"golang.org/x/image/font/gofont/gomonobold"

	"pluja.dev/kycnot.me/database"
)

func (s *Server) handleVerifyPow(c iris.Context) {
	// Get id, nonce and proof from the request
	id := c.Params().Get("id")
	nonce := c.Params().Get("nonce")

	// Verify the proof of work
	valid := s.PowChallenger.PowVerifyProof(id, nonce)

	// Return the result
	c.JSON(iris.Map{
		"valid":  valid,
		"status": iris.StatusOK,
	})
}

// Proxies the request to the logo URL of a service by its ID
func (s *Server) handleApiPicture(c iris.Context) {
	id := c.Params().Get("id")

	imgCacheKey := fmt.Sprintf("img-%s", id)
	cttCacheKey := fmt.Sprintf("ctt-%s", id)
	if imageData, err := s.Cache.Get(imgCacheKey); err == nil {
		if ctt, err := s.Cache.Get(cttCacheKey); err == nil {
			c.ContentType(string(ctt))
			c.StatusCode(iris.StatusOK)
			c.Write(imageData)
			return
		}
	}

	service, err := database.Pb.GetServiceById(id)
	if err != nil || service.LogoURL == "" {
		log.Error().Err(err).Msg("GetPicture: Could not get service or logo URL is empty")
		respondWithPlaceholder(c, service.Name)
		return
	}

	req, _ := http.NewRequest("GET", service.LogoURL, nil)
	req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.3")
	if len(service.Urls) > 0 {
		req.Header.Set("Referer", service.Urls[0])
	} else if len(service.OnionUrls) > 0 {
		req.Header.Set("Referer", service.OnionUrls[0])
	}

	resp, err := s.HttpClient.Do(req)
	if err != nil || resp.StatusCode != http.StatusOK {
		log.Debug().Err(err).Msgf("GetPicture: Could not get image for %s", service.Name)
		respondWithPlaceholder(c, service.Name)
		return
	}
	defer resp.Body.Close()

	bodyBytes, _ := io.ReadAll(resp.Body)
	if len(bodyBytes) == 0 {
		log.Error().Msg("GetPicture: Empty response body")
		respondWithPlaceholder(c, service.Name)
		return
	}

	contentType := resp.Header.Get("Content-Type")

	// For other formats, use the original content type
	c.ContentType(contentType)
	s.Cache.Set(cttCacheKey, []byte(contentType))

	s.Cache.Set(imgCacheKey, bodyBytes)
	c.StatusCode(iris.StatusOK)
	c.Write(bodyBytes)
}

func respondWithPlaceholder(c iris.Context, serviceName string) {
	if serviceName == "" {
		serviceName = "?"
	}
	firstLetter := strings.ToUpper(string(serviceName[0]))
	const width, height, margin = 250, 250, 15

	img := image.NewRGBA(image.Rect(0, 0, width, height))
	draw.Draw(img, img.Bounds(), &image.Uniform{color.Black}, image.Point{}, draw.Src)

	f, _ := truetype.Parse(gomonobold.TTF)
	ctx := freetype.NewContext()
	ctx.SetDPI(72)
	ctx.SetFont(f)
	ctx.SetFontSize(180)
	ctx.SetSrc(image.NewUniform(color.RGBA{0x84, 0xcc, 0x16, 0xff}))
	ctx.SetClip(img.Bounds())
	ctx.SetDst(img)

	face := truetype.NewFace(f, &truetype.Options{Size: 180})
	textWidth := font.MeasureString(face, firstLetter).Round()
	ascent, _ := face.Metrics().Ascent, face.Metrics().Descent
	textHeight := ascent.Ceil()

	x := (width - textWidth) / 2
	y := (height-textHeight)/2 + textHeight
	pt := freetype.Pt(x, y)

	ctx.DrawString(firstLetter, pt)

	var buf bytes.Buffer
	png.Encode(&buf, img)

	c.ContentType("image/png")
	c.StatusCode(iris.StatusOK)
	c.Write(buf.Bytes())
}
