package commerce

import (
	"context"
	"encoding/json"
	"errors"
	"strings"
	"time"

	"gorm.io/gorm"

	"qycw/go-server/internal/plugins"
)

func (s *Service) AdminGroupReadiness(ctx context.Context, groupID int64) (map[string]any, error) {
	var group ProductGroup
	if err := s.db.WithContext(ctx).Where("id = ?", groupID).First(&group).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, NotFound("product group not found")
		}
		return nil, err
	}
	var products []Product
	if err := s.db.WithContext(ctx).Where("group_id = ?", groupID).Order("sort_order ASC, id ASC").Find(&products).Error; err != nil {
		return nil, err
	}
	groupIssues := []map[string]any{}
	if group.Area == nil && group.Node == nil {
		groupIssues = append(groupIssues, readinessIssue("warning", "group", "产品组未绑定区域或节点"))
	}
	productResults := make([]map[string]any, 0, len(products))
	activeCount := 0
	allIssues := []map[string]any{}
	for _, product := range products {
		if product.Status == "active" {
			activeCount++
		}
		issues := s.productReadinessIssues(ctx, product)
		if product.Status == "active" {
			allIssues = append(allIssues, issues...)
		}
		productResults = append(productResults, map[string]any{
			"product_id":    product.ID,
			"sku":           product.SKU,
			"name":          product.Name,
			"status":        readinessStatus(issues),
			"error_count":   readinessCount(issues, "error"),
			"warning_count": readinessCount(issues, "warning"),
			"issues":        issues,
		})
	}
	if activeCount == 0 {
		groupIssues = append(groupIssues, readinessIssue("error", "group", "产品组下没有已上架的产品"))
	}
	allIssues = append(groupIssues, allIssues...)
	return map[string]any{
		"group": map[string]any{
			"id":                 group.ID,
			"name":               group.Name,
			"slug":               group.Slug,
			"requires_real_name": group.RequiresRealName,
			"area":               group.Area,
			"node":               group.Node,
			"os_count":           readinessOSCount(group.OSOptions),
		},
		"status": readinessStatus(allIssues),
		"summary": map[string]any{
			"product_count":       len(products),
			"active_server_count": activeCount,
			"error_count":         readinessCount(allIssues, "error"),
			"warning_count":       readinessCount(allIssues, "warning"),
		},
		"products_total":  len(products),
		"products_active": activeCount,
		"issues":          groupIssues,
		"group_issues":    groupIssues,
		"products":        productResults,
	}, nil
}

func (s *Service) productReadinessIssues(ctx context.Context, product Product) []map[string]any {
	issues := []map[string]any{}
	if strings.TrimSpace(product.SKU) == "" || strings.TrimSpace(product.Name) == "" {
		issues = append(issues, readinessIssue("error", "product", "产品名称或 SKU 不完整"))
	}
	var pricingCount int64
	if err := s.db.WithContext(ctx).Model(&ProductPricing{}).Where("product_id = ? AND is_enabled = ?", product.ID, true).Count(&pricingCount).Error; err != nil || pricingCount == 0 {
		issues = append(issues, readinessIssue("error", "pricing", "产品没有启用的价格周期"))
	}
	switch product.APIType {
	case "", "none":
		if product.AutoProvision {
			issues = append(issues, readinessIssue("error", "provision", "产品开启了自动开通，但没有配置开通方式"))
		} else {
			issues = append(issues, readinessIssue("warning", "provision", "产品没有配置自动开通方式，需要人工开通"))
		}
	case "generic_blank":
		issues = append(issues, readinessIssue("error", "provision", "通用空白产品应使用 plugin + generic_blank 配置"))
	case "plugin":
		if product.APIIdentifier == nil || strings.TrimSpace(*product.APIIdentifier) == "" {
			issues = append(issues, readinessIssue("error", "provision", "插件开通产品未选择开通插件"))
			break
		}
		if s.plugins == nil {
			issues = append(issues, readinessIssue("error", "provision", "插件运行时未启用"))
			break
		}
		manifest, err := s.plugins.Manifest(ctx, strings.TrimSpace(*product.APIIdentifier))
		if err != nil || !manifest.HasCapability(plugins.CapabilityProvision) {
			issues = append(issues, readinessIssue("error", "provision", "绑定的开通插件不存在或不支持开通能力"))
		} else if !manifest.Enabled {
			issues = append(issues, readinessIssue("error", "provision", "绑定的开通插件未启用"))
		}
	case "dcim_cloud_image", "dcim_cloud_rid", "zjmf_finance":
		if product.CloudServerID == nil {
			issues = append(issues, readinessIssue("error", "upstream", "产品未绑定上游接口"))
			break
		}
		server, err := s.adminCloudServer(ctx, *product.CloudServerID)
		if err != nil || server.Disabled {
			issues = append(issues, readinessIssue("error", "upstream", "绑定的上游接口不存在或已禁用"))
			break
		}
		if product.APIType == "zjmf_finance" && !isZJMFServer(server) {
			issues = append(issues, readinessIssue("error", "upstream", "产品开通方式是 ZJMF 财务，但绑定的上游不是 ZJMF 财务类型"))
		}
		if strings.HasPrefix(product.APIType, "dcim_cloud") && !isDCIMServer(server) {
			issues = append(issues, readinessIssue("error", "upstream", "产品开通方式是 DCIM 云服务器，但绑定的上游不是 DCIM 类型"))
		}
		if product.APIType == "dcim_cloud_image" && (product.APIIdentifier == nil || strings.TrimSpace(*product.APIIdentifier) == "") {
			issues = append(issues, readinessIssue("warning", "upstream", "镜像开通产品未填写默认镜像 ID；购买时必须选择系统镜像"))
		}
	default:
		issues = append(issues, readinessIssue("warning", "provision", "未知开通方式，实际开通时会尝试走插件兜底"))
	}
	return issues
}

func (s *Service) AdminRecalculateMembershipSpend(ctx context.Context) (map[string]any, error) {
	var users []UserAccount
	if err := s.db.WithContext(ctx).Select("id").Find(&users).Error; err != nil {
		return nil, err
	}
	updated := 0
	for _, user := range users {
		var spent int
		_ = s.db.WithContext(ctx).Model(&Order{}).
			Where("user_id = ? AND status IN ?", user.ID, []string{"paid", "completed", "success"}).
			Select("COALESCE(SUM(total_amount), 0)").Scan(&spent).Error
		levelID := s.memberLevelForSpent(ctx, spent)
		updates := map[string]any{"total_spent": spent}
		if levelID != nil {
			updates["member_level_id"] = *levelID
		}
		var count int64
		if err := s.db.WithContext(ctx).Table("user_memberships").Where("user_id = ?", user.ID).Count(&count).Error; err != nil {
			return nil, err
		}
		if count == 0 {
			row := map[string]any{"user_id": user.ID, "total_spent": spent, "total_points": 0, "available_points": 0, "member_level_locked": false}
			if levelID != nil {
				row["member_level_id"] = *levelID
				row["upgraded_at"] = time.Now().UTC()
			}
			if err := s.db.WithContext(ctx).Table("user_memberships").Create(row).Error; err != nil {
				return nil, err
			}
		} else if err := s.db.WithContext(ctx).Table("user_memberships").Where("user_id = ? AND member_level_locked = ?", user.ID, false).Updates(updates).Error; err != nil {
			return nil, err
		}
		updated++
	}
	return map[string]any{"updated": updated, "total_users": len(users)}, nil
}

func (s *Service) memberLevelForSpent(ctx context.Context, spent int) *int64 {
	var level MemberLevel
	err := s.db.WithContext(ctx).Where("enabled = ? AND min_total_spent <= ?", true, spent).Order("level DESC, min_total_spent DESC, id DESC").First(&level).Error
	if err != nil {
		return nil
	}
	return &level.ID
}

func readinessIssue(level string, scope string, message string) map[string]any {
	return map[string]any{"level": level, "scope": scope, "message": message}
}

func readinessStatus(issues []map[string]any) string {
	for _, issue := range issues {
		if issue["level"] == "error" {
			return "error"
		}
	}
	for _, issue := range issues {
		if issue["level"] == "warning" {
			return "warning"
		}
	}
	return "pass"
}

func readinessCount(issues []map[string]any, level string) int {
	count := 0
	for _, issue := range issues {
		if issue["level"] == level {
			count++
		}
	}
	return count
}

func readinessOSCount(raw JSONRaw) int {
	if len(raw) == 0 {
		return 0
	}
	var list []any
	if err := json.Unmarshal(raw, &list); err == nil {
		return len(list)
	}
	var object map[string]any
	if err := json.Unmarshal(raw, &object); err == nil {
		return len(object)
	}
	return 0
}
