package models

import (
	"strings"
	"time"
)

var activityLocation = time.FixedZone("Asia/Shanghai", 8*60*60)

const (
	// 日与时刻之间留空格，避免「20日11点」粘连难读
	ActivityTimeLayout = "2006年1月2日 15点04分05秒"
	// 历史数据可能无空格，解析时兼容
	activityTimeLayoutLegacy = "2006年1月2日15点04分05秒"
	ActivityDateLayout       = "2006-01-02"
)

func CurrentActivityDate() string {
	return time.Now().In(activityLocation).Format(ActivityDateLayout)
}

func CurrentActivityTime() string {
	return FormatActivityTime(time.Now())
}

func FormatActivityTime(t time.Time) string {
	return t.In(activityLocation).Format(ActivityTimeLayout)
}

func ParseActivityTime(value string) (time.Time, bool) {
	value = strings.TrimSpace(value)
	if value == "" {
		return time.Time{}, false
	}
	layouts := []string{ActivityTimeLayout, activityTimeLayoutLegacy, time.RFC3339Nano, time.RFC3339}
	for _, layout := range layouts {
		if parsed, err := time.ParseInLocation(layout, value, activityLocation); err == nil {
			return parsed.In(activityLocation), true
		}
		if parsed, err := time.Parse(layout, value); err == nil {
			return parsed.In(activityLocation), true
		}
	}
	return time.Time{}, false
}

func ActivityDate(value string) (string, bool) {
	parsed, ok := ParseActivityTime(value)
	if !ok {
		return "", false
	}
	return parsed.In(activityLocation).Format(ActivityDateLayout), true
}

func HasActivityDate(values []string, date string) bool {
	for _, value := range values {
		if parsedDate, ok := ActivityDate(value); ok && parsedDate == date {
			return true
		}
	}
	return false
}

func ActivitySummary(values []string, fallbackDate string) (days int, streak int, lastAt string) {
	dateSet := make(map[string]struct{}, len(values))
	var latest time.Time
	hasLatest := false

	for _, value := range values {
		parsed, ok := ParseActivityTime(value)
		if !ok {
			continue
		}
		dateKey := parsed.In(activityLocation).Format(ActivityDateLayout)
		dateSet[dateKey] = struct{}{}
		if !hasLatest || parsed.After(latest) {
			latest = parsed
			hasLatest = true
			lastAt = FormatActivityTime(parsed)
		}
	}

	if len(dateSet) == 0 && strings.TrimSpace(fallbackDate) != "" {
		dateSet[strings.TrimSpace(fallbackDate)] = struct{}{}
		days = 1
		streak = 1
		return
	}

	days = len(dateSet)
	if !hasLatest {
		return
	}

	cursor := time.Date(latest.In(activityLocation).Year(), latest.In(activityLocation).Month(), latest.In(activityLocation).Day(), 0, 0, 0, 0, activityLocation)
	for {
		key := cursor.Format(ActivityDateLayout)
		if _, ok := dateSet[key]; !ok {
			break
		}
		streak++
		cursor = cursor.AddDate(0, 0, -1)
	}

	return
}
