package gobackend

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"
)

// buildDownloadFilename renders the sanitized "<name><ext>" filename for req
// from its template/metadata, defaulting to "<artist> - <title>.flac".
func buildDownloadFilename(req DownloadRequest) string {
	metadata := map[string]any{
		"title":             req.TrackName,
		"artist":            req.ArtistName,
		"album":             req.AlbumName,
		"album_artist":      req.AlbumArtist,
		"track":             req.TrackNumber,
		"track_number":      req.TrackNumber,
		"total_tracks":      req.TotalTracks,
		"playlist_position": req.PlaylistPosition,
		"disc":              req.DiscNumber,
		"disc_number":       req.DiscNumber,
		"total_discs":       req.TotalDiscs,
		"year":              extractYear(req.ReleaseDate),
		"date":              req.ReleaseDate,
		"release_date":      req.ReleaseDate,
		"isrc":              req.ISRC,
		"provider":          req.DownloadProvider,
		"provider_id":       req.ProviderTrackID,
		"composer":          req.Composer,
		"quality":           req.Quality,
		"quality_variant":   req.QualityVariant,
	}

	filename := buildFilenameFromTemplate(req.FilenameFormat, metadata)
	if strings.TrimSpace(filename) == "" {
		filename = fmt.Sprintf("%s - %s", req.ArtistName, req.TrackName)
	}
	filename = sanitizeFilenamePreservingToken(filename, req.QualityVariant)

	ext := strings.TrimSpace(req.OutputExt)
	if ext == "" {
		ext = ".flac"
	} else if !strings.HasPrefix(ext, ".") {
		ext = "." + ext
	}

	return filename + ext
}

func resolvedDownloadFilename(req DownloadRequest, result DownloadResult, filePath string) string {
	resolved := req
	if isrc := strings.TrimSpace(result.ISRC); isrc != "" {
		resolved.ISRC = isrc
	}
	extension := strings.TrimSpace(result.ActualExtension)
	if extension == "" {
		extension = filepath.Ext(strings.TrimSpace(result.FilePath))
	}
	if extension == "" {
		extension = filepath.Ext(strings.TrimSpace(filePath))
	}
	if extension != "" {
		resolved.OutputExt = extension
	}
	return buildDownloadFilename(resolved)
}

func buildOutputPath(req DownloadRequest) string {
	if strings.TrimSpace(req.OutputPath) != "" {
		return strings.TrimSpace(req.OutputPath)
	}

	outputDir := req.OutputDir
	if strings.TrimSpace(outputDir) == "" {
		outputDir = filepath.Join(os.TempDir(), "spotiflac-downloads")
	}
	os.MkdirAll(outputDir, 0755)
	AddAllowedDownloadDir(outputDir)

	return filepath.Join(outputDir, buildDownloadFilename(req))
}

func buildOutputPathForExtension(req DownloadRequest, ext *loadedExtension) string {
	if strings.TrimSpace(req.OutputPath) != "" {
		outputPath := strings.TrimSpace(req.OutputPath)
		AddAllowedDownloadDir(filepath.Dir(outputPath))
		return outputPath
	}

	// SAF downloads hand extensions a detached output FD owned by the host.
	// Extensions still need a real local temp file so Android can copy it into
	// the target document after provider-specific post-processing completes.
	if !isFDOutput(req.OutputFD) && strings.TrimSpace(req.OutputDir) != "" {
		return buildOutputPath(req)
	}

	tempDir := filepath.Join(ext.DataDir, "downloads")
	os.MkdirAll(tempDir, 0755)
	AddAllowedDownloadDir(tempDir)

	return filepath.Join(tempDir, buildDownloadFilename(req))
}

func shouldReuseExistingOutput(req DownloadRequest, outputPath string) bool {
	if req.AllowQualityVariant || isFDOutput(req.OutputFD) {
		return false
	}
	path := strings.TrimSpace(outputPath)
	if path == "" || strings.HasPrefix(path, "content://") || strings.HasPrefix(path, "/proc/self/fd/") {
		return false
	}
	info, err := os.Stat(path)
	return err == nil && info.Mode().IsRegular() && info.Size() > 0
}

func canEmbedGenreLabel(filePath string) bool {
	path := strings.TrimSpace(filePath)
	if path == "" || strings.HasPrefix(path, "content://") || strings.HasPrefix(path, "/proc/self/fd/") {
		return false
	}
	if strings.ToLower(filepath.Ext(path)) != ".flac" {
		return false
	}
	if !filepath.IsAbs(path) {
		return false
	}
	info, err := os.Stat(path)
	return err == nil && !info.IsDir() && info.Size() > 0
}

func embedExtensionDownloadMetadata(resp DownloadResponse, req DownloadRequest, alreadyExists bool) {
	if alreadyExists || !req.EmbedMetadata {
		return
	}

	filePath := strings.TrimSpace(resp.FilePath)
	if !canEmbedGenreLabel(filePath) {
		if req.Genre != "" || req.Label != "" || resp.CoverURL != "" || req.CoverURL != "" {
			GoLog("[DownloadWithExtensionFallback] Skipping metadata/cover embed for non-local FLAC output path: %q\n", filePath)
		}
		return
	}

	coverURL := firstNonEmptyTrimmed(resp.CoverURL, req.CoverURL)
	var coverData []byte
	if coverURL != "" {
		data, err := downloadCoverToMemory(coverURL)
		if err != nil {
			GoLog("[DownloadWithExtensionFallback] Warning: failed to download cover for metadata embed: %v\n", err)
		} else if len(data) > 0 {
			coverData = data
		}
	}

	metadata := Metadata{
		Title:         firstNonEmptyTrimmed(resp.Title, req.TrackName),
		Artist:        firstNonEmptyTrimmed(resp.Artist, req.ArtistName),
		Album:         firstNonEmptyTrimmed(resp.Album, req.AlbumName),
		AlbumArtist:   firstNonEmptyTrimmed(resp.AlbumArtist, req.AlbumArtist),
		ArtistTagMode: req.ArtistTagMode,
		Date:          firstNonEmptyTrimmed(resp.ReleaseDate, req.ReleaseDate),
		TrackNumber:   firstPositiveInt(resp.TrackNumber, req.TrackNumber),
		TotalTracks:   firstPositiveInt(resp.TotalTracks, req.TotalTracks),
		DiscNumber:    firstPositiveInt(resp.DiscNumber, req.DiscNumber),
		TotalDiscs:    firstPositiveInt(resp.TotalDiscs, req.TotalDiscs),
		ISRC:          firstNonEmptyTrimmed(resp.ISRC, req.ISRC),
		Genre:         firstNonEmptyTrimmed(resp.Genre, req.Genre),
		Label:         firstNonEmptyTrimmed(resp.Label, req.Label),
		Copyright:     firstNonEmptyTrimmed(resp.Copyright, req.Copyright),
		Composer:      firstNonEmptyTrimmed(resp.Composer, req.Composer),
		Comment:       firstNonEmptyTrimmed(resp.Comment, req.Comment),
		Explicit:      resp.Explicit || req.Explicit,
		AlbumType:     firstNonEmptyTrimmed(resp.AlbumType, req.AlbumType),
		UPC:           firstNonEmptyTrimmed(resp.UPC, req.UPC),
	}
	if req.EmbedLyrics {
		metadata.Lyrics = resp.LyricsLRC
	}

	var err error
	if len(coverData) > 0 {
		err = EmbedMetadataWithCoverData(filePath, metadata, coverData)
	} else {
		err = EmbedMetadata(filePath, metadata, "")
	}
	if err != nil {
		GoLog("[DownloadWithExtensionFallback] Warning: failed to embed metadata/cover: %v\n", err)
		return
	}

	if len(coverData) > 0 {
		GoLog("[DownloadWithExtensionFallback] Embedded metadata and cover from %q\n", coverURL)
	} else {
		GoLog("[DownloadWithExtensionFallback] Embedded metadata without cover\n")
	}
}

func firstPositiveInt(values ...int) int {
	for _, value := range values {
		if value > 0 {
			return value
		}
	}
	return 0
}
