package batch

import (
	"strings"

	"sub2api-cn-relay-manager/internal/probe"
)

type ReuseInput struct {
	ProviderMatched          bool
	ProviderID               string
	CanonicalModelFamilies   []string
	MatchedAccountID         int64
	MatchedAccountState      MatchedAccountState
	ExistingProviderID       string
	ExistingAccessStatus     AccessStatus
	ExistingCanonicalFamilys []string
}

type ReuseDecision struct {
	ProvisionReused      bool
	ReusedFromProviderID string
	ReusedFromAccountID  int64
	MatchedAccountState  MatchedAccountState
	AccountResolution    AccountResolution
	FamilyCovered        bool
}

func DecideReuse(input ReuseInput) ReuseDecision {
	decision := ReuseDecision{
		MatchedAccountState: input.MatchedAccountState,
		AccountResolution:   AccountResolutionCreated,
		FamilyCovered:       canonicalFamiliesCovered(input.CanonicalModelFamilies, input.ExistingCanonicalFamilys),
	}

	if input.MatchedAccountState == "" {
		decision.MatchedAccountState = MatchedAccountStateNone
	}

	if !providerMatched(input) || !decision.FamilyCovered {
		return decision
	}

	if input.ExistingAccessStatus == AccessStatusBroken || input.MatchedAccountState == MatchedAccountStateBroken {
		decision.AccountResolution = AccountResolutionReplaced
		return decision
	}

	switch input.MatchedAccountState {
	case MatchedAccountStateDisabled, MatchedAccountStateDeprecated:
		decision.ProvisionReused = true
		decision.ReusedFromProviderID = strings.TrimSpace(input.ExistingProviderID)
		decision.ReusedFromAccountID = input.MatchedAccountID
		decision.AccountResolution = AccountResolutionReactivated
		return decision
	case MatchedAccountStateActive, MatchedAccountStateNone, "":
		decision.ProvisionReused = true
		decision.ReusedFromProviderID = strings.TrimSpace(input.ExistingProviderID)
		decision.ReusedFromAccountID = input.MatchedAccountID
		decision.AccountResolution = AccountResolutionReused
		return decision
	default:
		return decision
	}
}

func canonicalFamiliesCovered(requested []string, existing []string) bool {
	if len(requested) == 0 || len(existing) == 0 {
		return false
	}

	existingSet := make(map[string]struct{}, len(existing))
	for _, family := range existing {
		canonical := probe.CanonicalModelFamily(family)
		if canonical == "" {
			continue
		}
		existingSet[canonical] = struct{}{}
	}

	for _, family := range requested {
		canonical := probe.CanonicalModelFamily(family)
		if canonical == "" {
			return false
		}
		if _, ok := existingSet[canonical]; !ok {
			return false
		}
	}

	return true
}

func sameProvider(left, right string) bool {
	return strings.TrimSpace(left) != "" && strings.TrimSpace(left) == strings.TrimSpace(right)
}

func providerMatched(input ReuseInput) bool {
	if input.ProviderMatched {
		return true
	}
	return sameProvider(input.ProviderID, input.ExistingProviderID)
}
