package controller

import (
	"bytes"
	"crypto/rand"
	"encoding/hex"
	"image"

	"metazone.cc/metalab/internal/model"
	"metazone.cc/metalab/internal/service"

	"github.com/chai2010/webp"
	"github.com/gin-gonic/gin"
)

// PostController 帖子控制器（SSR 页面 + API）
type PostController struct {
	postService  postUseCase
	shortcodeSvc *service.ShortcodeService
}

// NewPostController 构造函数
func NewPostController(ps postUseCase, scs *service.ShortcodeService) *PostController {
	return &PostController{postService: ps, shortcodeSvc: scs}
}

// allowedImageExt 允许的图片扩展名
var allowedImageExt = map[string]bool{
	".jpg": true, ".jpeg": true, ".png": true, ".gif": true, ".webp": true,
}

// visitorCookieName Cookie 名称
const visitorCookieName = "visitor_id"

// visitorCookieMaxAge 访客 Cookie 有效期（30 天）
const visitorCookieMaxAge = 30 * 24 * 3600

// getVisitorID 获取或创建访客标识 Cookie
func (ctrl *PostController) getVisitorID(c *gin.Context) string {
	if cookie, err := c.Cookie(visitorCookieName); err == nil && cookie != "" {
		return cookie
	}
	// 生成 16 字节随机 hex（32 字符）
	b := make([]byte, 16)
	if _, err := rand.Read(b); err != nil {
		return ""
	}
	vid := hex.EncodeToString(b)
	c.SetCookie(visitorCookieName, vid, visitorCookieMaxAge, "/", "", false, true)
	return vid
}

// applyShortcode 处理帖子正文中的 shortcode 标记，替换为 HTML 占位符
func (ctrl *PostController) applyShortcode(post *model.Post) {
	if ctrl.shortcodeSvc != nil {
		result := ctrl.shortcodeSvc.Process(post.Body)
		post.Body = result.ProcessedBody
	}
}

// encodeWebPBinary 二分查找 WebP 质量，找 ≤ targetBytes 的最高质量（quality 1~80）
// 返回 nil 表示最低质量仍超限（几乎不可能发生），应由调用方回退原格式
func encodeWebPBinary(img image.Image, targetBytes int) []byte {
	var buf bytes.Buffer
	if err := webp.Encode(&buf, img, &webp.Options{Quality: 80}); err != nil {
		return nil
	}
	if buf.Len() <= targetBytes {
		return buf.Bytes()
	}

	low, high := 1, 80
	var best []byte
	for low <= high {
		mid := (low + high) / 2
		buf.Reset()
		if err := webp.Encode(&buf, img, &webp.Options{Quality: float32(mid)}); err != nil {
			return nil
		}
		if buf.Len() <= targetBytes {
			best = make([]byte, buf.Len())
			copy(best, buf.Bytes())
			low = mid + 1
		} else {
			high = mid - 1
		}
	}
	return best
}
