package blog

import (
	"bytes"
	_ "embed"
	"image"
	"image/png"
	"os"
	"path/filepath"
	"strings"

	"github.com/fogleman/gg"
	"github.com/golang/freetype/truetype"
	"golang.org/x/image/font"
)

//go:embed assets/OpenSans-Bold.ttf
var fontBoldBytes []byte

//go:embed assets/OpenSans-Regular.ttf
var fontRegularBytes []byte

//go:embed assets/og-base.png
var ogBaseImage []byte

var (
	fontBoldParsed    *truetype.Font
	fontRegularParsed *truetype.Font
)

func init() {
	fontBoldParsed, _ = truetype.Parse(fontBoldBytes)
	fontRegularParsed, _ = truetype.Parse(fontRegularBytes)
}

func makeFace(f *truetype.Font, size float64) font.Face {
	return truetype.NewFace(f, &truetype.Options{
		Size:    size,
		DPI:     72,
		Hinting: font.HintingFull,
	})
}

// Layout constants — adjust these to reposition text
const (
	ogW = 1200
	ogH = 630

	// Text section (left side)
	textX      = 60  // left padding for title/description
	textW      = 680 // max text width for wrapping
	textStartY = 195 // top of title block
	lineGap    = 12  // gap between title and description

	// Art section (right side) — domain and date centered here
	artStartX = 770 // left edge of art section
	artCX     = 985 // horizontal center of art section (770 + 430/2)
	domainX   = 1080
	dateX     = 1100
	domainY   = 590 // domain text Y
	dateY     = 30  // date text Y

	titleFontSize  = 56
	descFontSize   = 26
	domainFontSize = 22
	maxTitleLines  = 3
	maxDescLines   = 5
)

func ensureGeneratedOGImage(dir, slug, title, dateStr, description string) string {
	outPath := filepath.Join(dir, slug+".png")

	if _, err := os.Stat(outPath); err == nil {
		return outPath
	}

	if err := os.MkdirAll(dir, 0755); err != nil {
		return ""
	}

	img := generateOGImage(title, dateStr, description)

	f, err := os.Create(outPath)
	if err != nil {
		return ""
	}
	defer f.Close()
	png.Encode(f, img)

	return outPath
}

func generateOGImage(title, dateStr, description string) image.Image {
	// Decode the embedded base image
	baseImg, _, _ := image.Decode(bytes.NewReader(ogBaseImage))
	dc := gg.NewContext(ogW, ogH)
	dc.DrawImage(baseImg, 0, 0)

	// Domain name — centered in right art section, top
	dc.SetFontFace(makeFace(fontRegularParsed, domainFontSize))
	dc.SetRGBA(0.663, 0.639, 0.769, 0.8)
	dc.DrawStringAnchored("chaosmith.systems", float64(domainX), float64(domainY), 0.5, 0.9)

	// Date — centered in right art section, bottom
	if dateStr != "" {
		dc.SetRGBA(0.663, 0.639, 0.769, 0.6)
		dc.DrawStringAnchored(dateStr, float64(dateX), float64(dateY), 0.5, 0.9)
	}

	// Title — right section, top-aligned
	dc.SetFontFace(makeFace(fontBoldParsed, titleFontSize))
	dc.SetRGB(0.953, 0.941, 1.0)

	titleLines := wrapText(dc, title, float64(textW), maxTitleLines)
	currY := float64(textStartY)
	lineH := titleFontSize * 1.2
	for _, line := range titleLines {
		dc.DrawStringAnchored(line, float64(textX), currY, 0, 0.5)
		currY += lineH
	}

	// Description — below title
	currY += float64(lineGap)
	dc.SetFontFace(makeFace(fontRegularParsed, descFontSize))
	dc.SetRGBA(0.663, 0.639, 0.769, 0.8)

	descLines := wrapText(dc, description, float64(textW), maxDescLines)
	descLineH := descFontSize * 1.3
	for _, line := range descLines {
		dc.DrawStringAnchored(line, float64(textX), currY, 0, 0.5)
		currY += descLineH
	}

	return dc.Image()
}

func wrapText(dc *gg.Context, text string, maxW float64, maxLines int) []string {
	words := strings.Fields(text)
	if len(words) == 0 {
		return []string{""}
	}

	var lines []string
	curr := words[0]
	for _, w := range words[1:] {
		test := curr + " " + w
		width, _ := dc.MeasureString(test)
		if width > maxW {
			lines = append(lines, curr)
			curr = w
		} else {
			curr = test
		}
	}
	lines = append(lines, curr)

	if len(lines) > maxLines {
		lines = lines[:maxLines]
		last := lines[maxLines-1]
		if len(last) > 3 {
			last = last[:len(last)-3] + "..."
		}
		lines[maxLines-1] = last
	}

	return lines
}
