package usecase

import (
	"context"
	"fmt"
	"strings"
	"time"

	"apps/backend/internal/module/radar/domain"
	usageDomain "apps/backend/internal/module/usage/domain"
)

// GetCostPreview is deliberately read-only: it resolves the likely key mode
// and reads the current balance, but never calls PrepareCall or reserves a
// credit. The actual operation remains the only place that meters usage.
func (s *Service) GetCostPreview(ctx context.Context, ownerUID int64, action, watchID, productID string, candidateLimit int) (*domain.CostPreview, error) {
	if ownerUID <= 0 {
		return nil, fmt.Errorf("%w: owner_uid required", domain.ErrValidation)
	}
	action = strings.ToLower(strings.TrimSpace(action))
	if action != "sweep" && action != "explore" && action != "demand_map_enrich" && action != "reply" {
		return nil, fmt.Errorf("%w: unknown cost preview action %q", domain.ErrValidation, action)
	}
	if candidateLimit <= 0 {
		candidateLimit = 20
	}
	if candidateLimit > 100 {
		candidateLimit = 100
	}
	searchCalls := 0
	if action == "sweep" || action == "explore" {
		searchCalls = 1
		if productID != "" {
			if plan, err := s.BuildProductQueryPlan(ctx, ownerUID, productID); err == nil && len(plan.Groups) > 0 {
				searchCalls = len(plan.Groups)
			}
		}
	}
	maxAI := 0
	fixed := 0
	min := searchCalls * usageDomain.MeterCost(usageDomain.MeterWebSearch)
	max := min
	switch action {
	case "sweep", "explore":
		maxAI = candidateLimit
		max += maxAI * usageDomain.MeterCost(usageDomain.MeterAIResearch)
	case "demand_map_enrich", "reply":
		fixed = usageDomain.MeterCost(usageDomain.MeterAICopy)
		min, max = fixed, fixed
	}
	mode := usageDomain.KeyModePlatform
	meter := usageDomain.MeterWebSearch
	if action == "demand_map_enrich" || action == "reply" {
		meter = usageDomain.MeterAICopy
	}
	if s.ResolveKey != nil {
		if resolved, _, err := s.ResolveKey(ctx, ownerUID, meter); err == nil && resolved != "" {
			mode = resolved
		}
	}
	remaining := 0
	if s.Usage != nil {
		if summary, err := s.Usage.GetSummary(ctx, ownerUID, ""); err == nil && summary != nil {
			remaining = summary.Platform.CreditsRemaining
		}
	}
	return &domain.CostPreview{
		PreviewID: domain.NewID(), Action: action, KeyMode: mode,
		FixedCredits: fixed, MinCredits: min, MaxCredits: max,
		SearchCalls: searchCalls, MaxAICandidates: maxAI, RemainingCredits: remaining,
		EstimateBasis: "免費前處理；provider 成功後依 web_search／ai_research／ai_copy meter 計點",
		ExpiresAt:     time.Now().UTC().Add(5 * time.Minute).UnixNano(),
	}, nil
}
