// Package media 统一生成可长期稳定引用的 COS 媒体对象键和扩展名。
package media

import (
	"fmt"
	"path/filepath"
	"regexp"
	"strings"
	"time"

	"github.com/google/uuid"
)

const objectRoot = "juyou_ran"

var unsafeKeyPart = regexp.MustCompile(`[^a-z0-9-]+`)
var safeExtension = regexp.MustCompile(`^\.[a-z0-9]+$`)

// objectKey 为所有媒体对象添加统一的业务根目录，避免不同业务直接污染存储桶根目录。
func objectKey(format string, args ...any) string {
	return fmt.Sprintf(objectRoot+"/"+format, args...)
}

// Slug 将业务名称转换为受控英文路径片段；展示名称保留在数据库中。
func Slug(value, fallback string) string {
	value = strings.ToLower(strings.TrimSpace(value))
	value = unsafeKeyPart.ReplaceAllString(value, "-")
	value = strings.Trim(value, "-")
	if value == "" {
		value = fallback
	}
	if len(value) > 48 {
		value = strings.Trim(value[:48], "-")
	}
	return value
}

// Extension 根据媒体类型或安全的原文件扩展名生成对象扩展名。
func Extension(filename, contentType string) string {
	switch strings.ToLower(contentType) {
	case "image/jpeg":
		return ".jpg"
	case "image/png":
		return ".png"
	case "image/webp":
		return ".webp"
	case "image/gif":
		return ".gif"
	case "video/mp4":
		return ".mp4"
	case "video/webm":
		return ".webm"
	case "audio/mpeg":
		return ".mp3"
	case "audio/wav", "audio/x-wav":
		return ".wav"
	case "text/vtt":
		return ".vtt"
	}
	ext := strings.ToLower(filepath.Ext(filename))
	if len(ext) > 1 && len(ext) <= 8 && safeExtension.MatchString(ext) {
		return ext
	}
	return ".bin"
}

// EpisodeSource 返回剧集原视频的对象键。
func EpisodeSource(projectID uuid.UUID, episodeNo int, episodeID, assetID uuid.UUID, filename, contentType string) string {
	return objectKey("video-redraw/projects/%s/episodes/%03d-%s/source/%s-source%s", projectID, episodeNo, episodeID, assetID, Extension(filename, contentType))
}

// EpisodeSubtitle 返回剧集字幕的对象键。
func EpisodeSubtitle(projectID uuid.UUID, episodeNo int, episodeID, assetID uuid.UUID, filename, contentType string) string {
	return objectKey("video-redraw/projects/%s/episodes/%03d-%s/subtitles/%s-subtitle%s", projectID, episodeNo, episodeID, assetID, Extension(filename, contentType))
}

// ProjectSource 返回无剧集项目原视频的对象键。
func ProjectSource(projectID, assetID uuid.UUID, filename, contentType string) string {
	return objectKey("video-redraw/projects/%s/source/%s-source%s", projectID, assetID, Extension(filename, contentType))
}

// ProjectSubtitle 返回无剧集项目字幕的对象键。
func ProjectSubtitle(projectID, assetID uuid.UUID, filename, contentType string) string {
	return objectKey("video-redraw/projects/%s/subtitles/%s-subtitle%s", projectID, assetID, Extension(filename, contentType))
}

// AssetReference 返回项目资产参考媒体的对象键。
func AssetReference(projectID uuid.UUID, assetType string, assetID, mediaID uuid.UUID, filename, contentType string) string {
	return objectKey("video-redraw/projects/%s/assets/%s/%s/%s-reference%s", projectID, Slug(assetType, "custom"), assetID, mediaID, Extension(filename, contentType))
}

// ProductImageReference 返回独立图片生成工具参考图片的稳定对象键。
func ProductImageReference(userID, mediaID uuid.UUID, filename, contentType string) string {
	return objectKey("product-images/users/%s/references/%s%s", userID, mediaID, Extension(filename, contentType))
}

// AssetOutput 返回项目资产生成结果的对象键。
func AssetOutput(projectID uuid.UUID, assetType string, assetID, taskID, mediaID uuid.UUID, contentType string) string {
	return objectKey("video-redraw/projects/%s/assets/%s/%s/outputs/%s-%s-result%s", projectID, Slug(assetType, "custom"), assetID, taskID, mediaID, Extension("", contentTypeFor("image", contentType)))
}

// StoryboardFrame 返回剧集分镜抽帧的对象键。
func StoryboardFrame(projectID, episodeID, storyboardID, mediaID uuid.UUID, sequence int, timestampMS int64) string {
	return objectKey("video-redraw/projects/%s/episodes/%s/storyboards/%04d-%s/frames/%s-%010d.jpg", projectID, episodeID, sequence, storyboardID, mediaID, timestampMS)
}

// StoryboardAnalysis 返回剧集分镜反推原始响应的对象键。
func StoryboardAnalysis(projectID, episodeID, storyboardID, taskID, mediaID uuid.UUID, sequence int) string {
	return objectKey("video-redraw/projects/%s/episodes/%s/storyboards/%04d-%s/analysis/%s-%s-reverse.json", projectID, episodeID, sequence, storyboardID, taskID, mediaID)
}

// TaskOutput 返回剧集分镜生成结果的对象键。
func TaskOutput(projectID, episodeID uuid.UUID, sequence int, taskID, mediaID uuid.UUID, outputType, contentType string) string {
	return objectKey("video-redraw/projects/%s/episodes/%s/storyboards/%04d/outputs/%s-%s-result%s", projectID, episodeID, sequence, taskID, mediaID, Extension("", contentTypeFor(outputType, contentType)))
}

// ProjectStoryboardFrame 返回无剧集项目分镜抽帧的对象键。
func ProjectStoryboardFrame(projectID, storyboardID, mediaID uuid.UUID, sequence int, timestampMS int64) string {
	return objectKey("video-redraw/projects/%s/storyboards/%04d-%s/frames/%s-%010d.jpg", projectID, sequence, storyboardID, mediaID, timestampMS)
}

// ProjectStoryboardAnalysis 返回无剧集项目分镜反推原始响应的对象键。
func ProjectStoryboardAnalysis(projectID, storyboardID, taskID, mediaID uuid.UUID, sequence int) string {
	return objectKey("video-redraw/projects/%s/storyboards/%04d-%s/analysis/%s-%s-reverse.json", projectID, sequence, storyboardID, taskID, mediaID)
}

// ProjectTaskOutput 返回无剧集项目分镜生成结果的对象键。
func ProjectTaskOutput(projectID uuid.UUID, sequence int, taskID, mediaID uuid.UUID, outputType, contentType string) string {
	return objectKey("video-redraw/projects/%s/storyboards/%04d/outputs/%s-%s-result%s", projectID, sequence, taskID, mediaID, Extension("", contentTypeFor(outputType, contentType)))
}

// StyleImage 返回管理端风格图片的统一对象键。
func StyleImage(mediaID uuid.UUID, extension string) string {
	return objectKey("styles/%s/%s%s", time.Now().Format("2006/01"), mediaID, extension)
}

// UserAvatar 返回用户头像的统一对象键。
func UserAvatar(userID, mediaID uuid.UUID, extension string) string {
	return objectKey("users/%s/avatar/%s%s", userID, mediaID, extension)
}

// StandaloneTaskOutput 返回独立生成任务的结果对象键。
func StandaloneTaskOutput(userID, taskID uuid.UUID, outputType, contentType string) string {
	return objectKey("users/%s/tasks/%s/output-1%s", userID, taskID, Extension("", contentTypeFor(outputType, contentType)))
}

// contentTypeFor 返回已知内容类型，缺省时根据输出类型选择默认媒体类型。
func contentTypeFor(outputType, contentType string) string {
	if contentType != "" {
		return contentType
	}
	if outputType == "image" {
		return "image/png"
	}
	return "video/mp4"
}
