package service

import (
	"regexp"
	"strings"
)

type ReleaseInfo struct {
	Title        string `json:"title"`
	Resolution   string `json:"resolution"`
	Source       string `json:"source"`
	VideoCodec   string `json:"video_codec"`
	AudioFormat  string `json:"audio_format"`
	ReleaseGroup string `json:"release_group"`
	ParseWarning bool   `json:"parse_warning"`
}

type ReleaseParser struct{}

func NewReleaseParser() *ReleaseParser {
	return &ReleaseParser{}
}

var (
	bracketRe = regexp.MustCompile(`\[.*?\]`)
	releaseRe = regexp.MustCompile(`(?i)` +
		`(?:.*?[-. ])?` +
		`(?:(?P<resolution>480[p|i]|576[p|i]|720[p|i]|1080[p|i]|2160[p|i]|4K)[-. ])?` +
		`(?:(?P<source>HDTV|PDTV|SDTV|WEB-DL|WEBDL|WEBRip|WEB\s|BluRay|BDRip|BRRip|REMUX|Remux|DVDRip|DVD|CAM|TS|HDCAM)[-. ])?` +
		`(?:(?P<codec>x264|h264|X264|H264|x265|h265|X265|HEVC|XviD|MPEG2|VC1|AV1)[-. ])?` +
		`(?:(?P<audio>DTS-HD\.MA|DTS-HD|DTS\.HD|DTS-X|DTS\.X|ATMOS|Atmos|TrueHD|DDP5\.1|DD\+?5\.1|DolbyDigitalPlus|AAC[. ]?2\.0|AAC[. ]?5\.1|AAC|AC3|DD|FLAC|MP3)[-. ])?` +
		`.*?(?:-(?P<group>[A-Za-z0-9]+))?$`,
	)

	resolutionCleanRe = regexp.MustCompile(`(?i)(480)[pi]|(576)[pi]|(720)[pi]|(1080)[pi]|(2160)[pi]|4K`)

	knownSuffixes = []string{"Esubs", "TGx", "ettv", "eztv", "x0r", "FGT", "ION10", "NTb"}
)

func normalizeResolution(raw string) string {
	if raw == "" {
		return ""
	}
	raw = strings.TrimSpace(raw)
	raw = strings.TrimRight(raw, "pPiI")
	if strings.EqualFold(raw, "4K") {
		return "2160p"
	}
	return raw + "p"
}

func normalizeSource(raw string) string {
	if raw == "" {
		return ""
	}
	raw = strings.TrimSpace(raw)
	raw = strings.TrimRight(raw, " -.")
	upper := strings.ToUpper(raw)
	switch {
	case upper == "HDTV", upper == "PDTV", upper == "SDTV":
		return upper
	case upper == "WEB-DL", upper == "WEBDL", strings.HasPrefix(upper, "WEB"):
		return "WEB-DL"
	case strings.HasPrefix(upper, "BLURAY"), upper == "BDRIP", upper == "BRRIP":
		return "BluRay"
	case upper == "REMUX":
		return "REMUX"
	case strings.HasPrefix(upper, "DVD"):
		return "DVD"
	case upper == "CAM", upper == "TS", upper == "HDCAM":
		return upper
	}
	return raw
}

func normalizeCodec(raw string) string {
	if raw == "" {
		return ""
	}
	raw = strings.TrimSpace(raw)
	switch {
	case strings.EqualFold(raw, "x264"), strings.EqualFold(raw, "h264"):
		return "x264"
	case strings.EqualFold(raw, "x265"), strings.EqualFold(raw, "h265"), strings.EqualFold(raw, "HEVC"):
		return "x265"
	case strings.EqualFold(raw, "XviD"):
		return "XviD"
	case strings.EqualFold(raw, "MPEG2"):
		return "MPEG2"
	case strings.EqualFold(raw, "VC1"):
		return "VC1"
	case strings.EqualFold(raw, "AV1"):
		return "AV1"
	}
	return raw
}

func normalizeAudio(raw string) string {
	if raw == "" {
		return ""
	}
	raw = strings.TrimSpace(raw)
	upper := strings.ToUpper(raw)
	switch {
	case strings.HasPrefix(upper, "DTS-HD"):
		return "DTS-HD"
	case strings.HasPrefix(upper, "DTS-X") || strings.HasPrefix(upper, "DTS.X"):
		return "DTS-X"
	case upper == "ATMOS":
		return "ATMOS"
	case upper == "TRUEHD":
		return "TrueHD"
	case strings.HasPrefix(upper, "DDP") || strings.HasPrefix(upper, "DD+") || strings.HasPrefix(upper, "DOLBYDIGITALPLUS"):
		return "DDP5.1"
	case strings.HasPrefix(upper, "DD") && (strings.Contains(upper, "5.1") || strings.Contains(upper, "51")):
		return "DDP5.1"
	case upper == "AAC":
		return "AAC"
	case strings.HasPrefix(upper, "AAC"):
		return "AAC"
	case upper == "AC3":
		return "AC3"
	case upper == "DD":
		return "DD"
	case upper == "FLAC":
		return "FLAC"
	case upper == "MP3":
		return "MP3"
	}
	return raw
}

func cleanGroup(raw string) string {
	if raw == "" {
		return ""
	}
	for _, suffix := range knownSuffixes {
		if strings.EqualFold(raw, suffix) {
			return ""
		}
	}
	return raw
}

func (p *ReleaseParser) Parse(title string) ReleaseInfo {
	info := ReleaseInfo{Title: title}

	cleaned := bracketRe.ReplaceAllString(title, " ")
	cleaned = strings.TrimSpace(cleaned)

	match := releaseRe.FindStringSubmatch(cleaned)
	if match == nil {
		info.ParseWarning = true
		return info
	}

	for i, name := range releaseRe.SubexpNames() {
		if i == 0 || name == "" {
			continue
		}
		value := match[i]
		switch name {
		case "resolution":
			info.Resolution = normalizeResolution(value)
		case "source":
			info.Source = normalizeSource(value)
		case "codec":
			info.VideoCodec = normalizeCodec(value)
		case "audio":
			info.AudioFormat = normalizeAudio(value)
		case "group":
			info.ReleaseGroup = cleanGroup(value)
		}
	}

	if info.Resolution == "" {
		info.ParseWarning = true
	}

	return info
}

func (p *ReleaseParser) MatchQuality(info ReleaseInfo) *QualityTier {
	for i := len(QualityTiers) - 1; i >= 0; i-- {
		tier := &QualityTiers[i]
		if tier.Resolution != "" && tier.Resolution != info.Resolution {
			continue
		}
		if info.Source == "" || SourceMatch(tier.Source, info.Source) {
			return tier
		}
	}

	return &QualityTiers[0]
}
