package photos

import (
	"sort"
	"strings"
	"time"

	"github.com/ultisuite/ulti-backend/internal/api/paginate"
	"github.com/ultisuite/ulti-backend/internal/api/query"
	photospkg "github.com/ultisuite/ulti-backend/internal/photos"
)

var photosTimeFormats = []string{
	time.RFC3339Nano,
	time.RFC3339,
	"2006-01-02T15:04:05.000Z",
	"2006-01-02",
}

func parsePhotosTime(raw string) (time.Time, bool) {
	raw = strings.TrimSpace(raw)
	if raw == "" {
		return time.Time{}, false
	}
	for _, layout := range photosTimeFormats {
		if t, err := time.Parse(layout, raw); err == nil {
			return t.UTC(), true
		}
	}
	return time.Time{}, false
}

func parseSortField(sort string) (field string, desc bool) {
	sort = strings.TrimSpace(sort)
	if sort == "" {
		return "created_at", true
	}
	if strings.HasPrefix(sort, "-") {
		return strings.TrimPrefix(sort, "-"), true
	}
	return sort, false
}

func assetMatchesDate(a photospkg.Asset, from, to *time.Time) bool {
	if from == nil && to == nil {
		return true
	}
	created, ok := parsePhotosTime(a.CreatedAt)
	if !ok {
		return false
	}
	if from != nil && created.Before(*from) {
		return false
	}
	if to != nil && created.After(*to) {
		return false
	}
	return true
}

func albumMatchesDate(a photospkg.Album, from, to *time.Time) bool {
	if from == nil && to == nil {
		return true
	}
	created, ok := parsePhotosTime(a.CreatedAt)
	if !ok {
		return false
	}
	if from != nil && created.Before(*from) {
		return false
	}
	if to != nil && created.After(*to) {
		return false
	}
	return true
}

func filterAssets(assets []photospkg.Asset, params query.ListParams) []photospkg.Asset {
	q := strings.ToLower(strings.TrimSpace(params.Q))
	out := make([]photospkg.Asset, 0, len(assets))
	for _, a := range assets {
		if q != "" {
			if !strings.Contains(strings.ToLower(a.OriginalName), q) &&
				!strings.Contains(strings.ToLower(a.MimeType), q) {
				continue
			}
		}
		if !assetMatchesDate(a, params.From, params.To) {
			continue
		}
		out = append(out, a)
	}
	return out
}

func filterAlbums(albums []photospkg.Album, params query.ListParams) []photospkg.Album {
	q := strings.ToLower(strings.TrimSpace(params.Q))
	out := make([]photospkg.Album, 0, len(albums))
	for _, a := range albums {
		if q != "" && !strings.Contains(strings.ToLower(a.Name), q) {
			continue
		}
		if !albumMatchesDate(a, params.From, params.To) {
			continue
		}
		out = append(out, a)
	}
	return out
}

func sortAssets(assets []photospkg.Asset, sortParam string) {
	field, desc := parseSortField(sortParam)
	sort.SliceStable(assets, func(i, j int) bool {
		if desc {
			return compareAssets(assets[j], assets[i], field)
		}
		return compareAssets(assets[i], assets[j], field)
	})
}

func compareAssets(a, b photospkg.Asset, field string) bool {
	switch field {
	case "name":
		return strings.ToLower(a.OriginalName) < strings.ToLower(b.OriginalName)
	case "size":
		return a.FileSize < b.FileSize
	default: // created_at
		ti, okI := parsePhotosTime(a.CreatedAt)
		tj, okJ := parsePhotosTime(b.CreatedAt)
		if okI && okJ {
			return ti.Before(tj)
		}
		return a.CreatedAt < b.CreatedAt
	}
}

func sortAlbums(albums []photospkg.Album, sortParam string) {
	field, desc := parseSortField(sortParam)
	sort.SliceStable(albums, func(i, j int) bool {
		if desc {
			return compareAlbums(albums[j], albums[i], field)
		}
		return compareAlbums(albums[i], albums[j], field)
	})
}

func compareAlbums(a, b photospkg.Album, field string) bool {
	switch field {
	case "name":
		return strings.ToLower(a.Name) < strings.ToLower(b.Name)
	case "size":
		return a.AssetCount < b.AssetCount
	default: // created_at
		ti, okI := parsePhotosTime(a.CreatedAt)
		tj, okJ := parsePhotosTime(b.CreatedAt)
		if okI && okJ {
			return ti.Before(tj)
		}
		return a.CreatedAt < b.CreatedAt
	}
}

func applyAssetList(assets []photospkg.Asset, params query.ListParams) ([]photospkg.Asset, int64) {
	filtered := filterAssets(assets, params)
	sortAssets(filtered, params.Sort)
	return paginate.Slice(filtered, params.Offset(), params.Limit())
}

func applyAlbumList(albums []photospkg.Album, params query.ListParams) ([]photospkg.Album, int64) {
	filtered := filterAlbums(albums, params)
	sortAlbums(filtered, params.Sort)
	return paginate.Slice(filtered, params.Offset(), params.Limit())
}
