// Playback profile generation is adapted from Wholphin's DeviceProfileUtils.kt,
// itself derived from Jellyfin Android TV.
//
// Wholphin: https://github.com/damontecres/Wholphin
// Jellyfin Android TV: https://github.com/jellyfin/jellyfin-androidtv
//
// Modifications Copyright (C) 2026 Memby contributors
// SPDX-License-Identifier: GPL-2.0-only
package emby

import "strconv"

// PlaybackCapabilities is the Android decoder evidence captured for one TV session.
// Zero values deliberately describe the legacy H.264-safe profile.
type PlaybackCapabilities struct {
	H264Profiles    []string
	H264Level       int
	H264High10Level int
	H264MaxWidth    int
	H264MaxHeight   int
	HEVC            bool
	HEVCMain        bool
	HEVCMain10      bool
	HEVCMainLevel   int
	HEVCMain10Level int
	HEVCMaxWidth    int
	HEVCMaxHeight   int
	HEVCHDR10       bool
	HEVCHDR10Plus   bool
	HEVCDolbyVision bool
}

func androidTVDeviceProfile(capabilities PlaybackCapabilities) map[string]any {
	videoCodecs := directPlayVideoCodecs(capabilities.HEVC)
	return map[string]any{
		"Name": "Memby Android TV", "SupportedMediaTypes": "Video",
		"DirectPlayProfiles": []map[string]string{
			{
				"Container": "mkv,mp4,m4v,mov,ts,mpegts", "VideoCodec": videoCodecs,
				"AudioCodec": "aac,mp3", "Type": "Video",
			},
		},
		"TranscodingProfiles": []map[string]string{
			{
				// AllowVideoStreamCopy lets Emby keep a supported H.264/HEVC track and
				// convert only incompatible audio or subtitles into an HLS stream.
				"Container": "ts", "VideoCodec": videoCodecs, "AudioCodec": "aac",
				"Protocol": "hls", "Type": "Video", "Context": "Streaming",
			},
		},
		"CodecProfiles":    videoCodecProfiles(capabilities),
		"SubtitleProfiles": androidTVSubtitleProfiles(),
	}
}

func androidTVSubtitleProfiles() []map[string]string {
	return []map[string]string{
		{"Format": "srt", "Method": "External"},
		{"Format": "subrip", "Method": "External"},
		{"Format": "ass", "Method": "External"},
		{"Format": "ssa", "Method": "External"},
		{"Format": "vtt", "Method": "External"},
		{"Format": "webvtt", "Method": "External"},
		{"Format": "mov_text", "Method": "External"},
		{"Format": "tx3g", "Method": "External"},
		{"Format": "pgs", "Method": "Encode"},
		{"Format": "pgssub", "Method": "Encode"},
		{"Format": "sup", "Method": "Encode"},
		{"Format": "vobsub", "Method": "Encode"},
		{"Format": "dvdsub", "Method": "Encode"},
	}
}

func videoCodecProfiles(capabilities PlaybackCapabilities) []map[string]any {
	profiles := []map[string]any{}
	if len(capabilities.H264Profiles) > 0 {
		profiles = append(profiles, codecProfile("h264",
			[]map[string]any{profileCondition("EqualsAny", "VideoProfile", joinProfiles(capabilities.H264Profiles))}, nil))
	}
	profiles = appendLevelProfile(
		profiles, "h264", capabilities.H264Level, "baseline|constrained baseline|main|high",
	)
	profiles = appendLevelProfile(profiles, "h264", capabilities.H264High10Level, "high 10")
	profiles = appendResolutionProfile(
		profiles, "h264", capabilities.H264MaxWidth, capabilities.H264MaxHeight,
	)
	if !capabilities.HEVC {
		return profiles
	}

	hevcProfiles := []string{}
	if capabilities.HEVCMain {
		hevcProfiles = append(hevcProfiles, "main")
	}
	if capabilities.HEVCMain10 {
		hevcProfiles = append(hevcProfiles, "main 10")
	}
	if len(hevcProfiles) > 0 {
		profiles = append(profiles, codecProfile("hevc",
			[]map[string]any{profileCondition("EqualsAny", "VideoProfile", joinProfiles(hevcProfiles))}, nil))
	}
	profiles = appendLevelProfile(profiles, "hevc", capabilities.HEVCMainLevel, "main")
	profiles = appendLevelProfile(profiles, "hevc", capabilities.HEVCMain10Level, "main 10")
	profiles = appendResolutionProfile(
		profiles, "hevc", capabilities.HEVCMaxWidth, capabilities.HEVCMaxHeight,
	)
	return profiles
}

func appendLevelProfile(profiles []map[string]any, codec string, level int, applyTo string) []map[string]any {
	if level <= 0 {
		return profiles
	}
	condition := "Equals"
	if containsPipe(applyTo) {
		condition = "EqualsAny"
	}
	return append(profiles, codecProfile(codec,
		[]map[string]any{profileCondition("LessThanEqual", "VideoLevel", strconv.Itoa(level))},
		[]map[string]any{profileCondition(condition, "VideoProfile", applyTo)}))
}

func appendResolutionProfile(profiles []map[string]any, codec string, width, height int) []map[string]any {
	if width <= 0 || height <= 0 {
		return profiles
	}
	return append(profiles, codecProfile(codec, []map[string]any{
		profileCondition("LessThanEqual", "Width", strconv.Itoa(width)),
		profileCondition("LessThanEqual", "Height", strconv.Itoa(height)),
	}, nil))
}

func codecProfile(codec string, conditions, applyConditions []map[string]any) map[string]any {
	profile := map[string]any{
		"Type": "Video", "Codec": codec, "Conditions": conditions,
	}
	if len(applyConditions) > 0 {
		profile["ApplyConditions"] = applyConditions
	}
	return profile
}

func profileCondition(condition, property, value string) map[string]any {
	return map[string]any{
		"Condition": condition, "Property": property, "Value": value, "IsRequired": false,
	}
}

func joinProfiles(values []string) string {
	result := ""
	for _, value := range values {
		if result != "" {
			result += "|"
		}
		result += value
	}
	return result
}

func containsPipe(value string) bool {
	for _, char := range value {
		if char == '|' {
			return true
		}
	}
	return false
}
