package opscenter

import (
	"context"
	"sort"
	"strings"
	"time"

	"hyapp-admin-server/internal/modules/appregistry"
	"hyapp-admin-server/internal/modules/luckygift"
	"hyapp-admin-server/internal/response"

	"github.com/gin-gonic/gin"
)

type Handler struct {
	apps      *appregistry.Service
	luckyGift *luckygift.Handler
}

type appDTO struct {
	AppID       int64  `json:"app_id"`
	AppCode     string `json:"app_code"`
	AppName     string `json:"app_name"`
	PackageName string `json:"package_name"`
	Platform    string `json:"platform"`
	Status      string `json:"status"`
	Source      string `json:"source"`
	CreatedAtMS int64  `json:"created_at_ms"`
	UpdatedAtMS int64  `json:"updated_at_ms"`
}

func New(apps *appregistry.Service, luckyGift *luckygift.Handler) *Handler {
	return &Handler{apps: apps, luckyGift: luckyGift}
}

func (h *Handler) ListApps(c *gin.Context) {
	ctx, cancel := context.WithTimeout(c.Request.Context(), 3*time.Second)
	defer cancel()

	items := make([]appDTO, 0, 4)
	if h.apps != nil {
		registryApps, err := h.apps.ListApps(ctx)
		if err != nil {
			response.ServerError(c, "获取应用列表失败")
			return
		}
		for _, item := range registryApps {
			items = append(items, appDTO{
				AppID:       item.AppID,
				AppCode:     strings.ToLower(strings.TrimSpace(item.AppCode)),
				AppName:     strings.TrimSpace(item.AppName),
				PackageName: strings.TrimSpace(item.PackageName),
				Platform:    strings.TrimSpace(item.Platform),
				Status:      strings.TrimSpace(item.Status),
				Source:      "registry",
				CreatedAtMS: item.CreatedAtMs,
				UpdatedAtMS: item.UpdatedAtMs,
			})
		}
	}

	// ops-center 的外部幸运礼物接入只认 app_code。这里强制补齐 yumi/aslan，使运营首屏能配置外部 App，
	// 但不反向写入 admin app registry，避免把临时接入白名单伪装成完整 App 主数据。
	nowMS := time.Now().UTC().UnixMilli()
	items = append(items,
		appDTO{AppCode: "yumi", AppName: "Yumi", Status: "active", Source: "fixed", CreatedAtMS: nowMS, UpdatedAtMS: nowMS},
		appDTO{AppCode: "aslan", AppName: "Aslan", Status: "active", Source: "fixed", CreatedAtMS: nowMS, UpdatedAtMS: nowMS},
	)

	items = filterApps(dedupeApps(items), c.Query("app_code"), c.Query("status"))
	response.OK(c, gin.H{"items": items, "total": len(items)})
}

func filterApps(items []appDTO, appCode string, status string) []appDTO {
	appCode = strings.ToLower(strings.TrimSpace(appCode))
	status = strings.ToLower(strings.TrimSpace(status))
	if appCode == "" && status == "" {
		return items
	}
	filtered := make([]appDTO, 0, len(items))
	for _, item := range items {
		if appCode != "" && !strings.Contains(strings.ToLower(item.AppCode), appCode) {
			continue
		}
		if status != "" && strings.ToLower(item.Status) != status {
			continue
		}
		filtered = append(filtered, item)
	}
	return filtered
}

func dedupeApps(items []appDTO) []appDTO {
	seen := make(map[string]appDTO, len(items))
	for _, item := range items {
		code := strings.ToLower(strings.TrimSpace(item.AppCode))
		if code == "" {
			continue
		}
		item.AppCode = code
		if item.AppName == "" {
			item.AppName = code
		}
		if item.Status == "" {
			item.Status = "active"
		}
		// registry 里已存在同 app_code 时以真实主数据为准；固定 app 只补缺口，不覆盖包名、平台和时间戳。
		if existing, ok := seen[code]; ok && existing.Source == "registry" {
			continue
		}
		seen[code] = item
	}
	result := make([]appDTO, 0, len(seen))
	for _, item := range seen {
		result = append(result, item)
	}
	sort.Slice(result, func(i, j int) bool {
		if result[i].Source != result[j].Source {
			return result[i].Source == "registry"
		}
		return result[i].AppCode < result[j].AppCode
	})
	return result
}
