package service

import (
	"bytes"
	"errors"
	"fmt"
	"image"
	"image/gif"
	"io"
	"mime/multipart"
	"path/filepath"
	"strings"

	"github.com/KarpelesLab/gowebp"

	// 注册解码器
	_ "image/jpeg"
	_ "image/png"

	_ "golang.org/x/image/webp"
)

// 图片展示方案（上传时同时保留原图与 WebP，按此决定返回给前端的 URL）
const (
	ImageDeliveryWebP     = "webp"     // 使用 WebP（默认，省流量）
	ImageDeliveryOriginal = "original" // 使用原图
)

const (
	// UploadWebPQuality 上传衍生 WebP 有损质量（0–100）
	UploadWebPQuality float32 = 82
	// UploadWebPMethod 编码档位：3 速度与体积较均衡
	UploadWebPMethod = 3
	// ThumbWebPQuality 帖子预览图质量
	ThumbWebPQuality float32 = 80
)

// preparedUpload 原图 + 可选 WebP 衍生
type preparedUpload struct {
	OrigExt         string // 含点，如 .jpg
	OrigContentType string
	OrigData        []byte
	WebPData        []byte // 空表示无衍生（动图 GIF，或原图已是 WebP）
}

// prepareUploadImage 始终保留原图字节；静态图额外生成 WebP 衍生
func prepareUploadImage(file *multipart.FileHeader) (*preparedUpload, error) {
	ext := strings.ToLower(filepath.Ext(file.Filename))
	if !allowedImageExt[ext] {
		return nil, errors.New("仅支持 jpg/png/gif/webp 格式")
	}
	if ext == ".jpeg" {
		ext = ".jpg"
	}

	src, err := file.Open()
	if err != nil {
		return nil, err
	}
	defer src.Close()

	raw, err := io.ReadAll(src)
	if err != nil {
		return nil, err
	}
	if len(raw) == 0 {
		return nil, errors.New("空图片文件")
	}

	out := &preparedUpload{
		OrigExt:         ext,
		OrigContentType: imageContentType(ext),
		OrigData:        raw,
	}

	// 动图 GIF：只保留原文件
	if ext == ".gif" && gifFrameCount(raw) > 1 {
		return out, nil
	}
	// 上传已是 WebP：原图即 WebP，不再重复衍生
	if ext == ".webp" {
		return out, nil
	}

	img, _, err := image.Decode(bytes.NewReader(raw))
	if err != nil {
		return nil, fmt.Errorf("解码图片失败: %w", err)
	}

	webpBytes, err := encodeWebPBytes(img, UploadWebPQuality, UploadWebPMethod)
	if err != nil {
		return nil, fmt.Errorf("转换 WebP 失败: %w", err)
	}
	out.WebPData = webpBytes
	return out, nil
}

func gifFrameCount(raw []byte) int {
	g, err := gif.DecodeAll(bytes.NewReader(raw))
	if err != nil || g == nil {
		return 0
	}
	return len(g.Image)
}

func encodeWebPBytes(img image.Image, quality float32, method int) ([]byte, error) {
	var buf bytes.Buffer
	if err := gowebp.Encode(&buf, img, &gowebp.Options{
		Lossy:   true,
		Quality: quality,
		Method:  method,
	}); err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

func normalizeImageDelivery(raw string) string {
	if strings.ToLower(strings.TrimSpace(raw)) == ImageDeliveryOriginal {
		return ImageDeliveryOriginal
	}
	return ImageDeliveryWebP
}

func imageContentType(ext string) string {
	switch strings.ToLower(ext) {
	case ".jpg", ".jpeg":
		return "image/jpeg"
	case ".png":
		return "image/png"
	case ".gif":
		return "image/gif"
	case ".webp":
		return "image/webp"
	default:
		return "application/octet-stream"
	}
}

// siblingUploadExts 同主文件名可能存在的伴生扩展名（删除时一并清理）
func siblingUploadExts(ext string) []string {
	ext = strings.ToLower(ext)
	all := []string{".jpg", ".jpeg", ".png", ".gif", ".webp"}
	out := make([]string, 0, len(all))
	for _, e := range all {
		if e == ext || (ext == ".jpg" && e == ".jpeg") || (ext == ".jpeg" && e == ".jpg") {
			continue
		}
		out = append(out, e)
	}
	return out
}
