package provision

import (
	"context"
	"strings"

	"sub2api-cn-relay-manager/internal/pack"
	"sub2api-cn-relay-manager/internal/store/sqlite"
)

type ModeAccessStatuses struct {
	Subscription string
	SelfService  string
}

func SuggestResourceNamesForMode(provider pack.ProviderManifest, accessMode string) ResourceNames {
	base := SuggestResourceNames(provider)
	suffix := accessModeResourceSuffix(accessMode)
	if suffix == "" {
		return base
	}
	return ResourceNames{
		Group:   appendResourceNameSuffix(base.Group, suffix),
		Channel: appendResourceNameSuffix(base.Channel, suffix),
		Plan:    appendResourceNameSuffix(base.Plan, suffix),
	}
}

func accessModeResourceSuffix(accessMode string) string {
	switch strings.TrimSpace(accessMode) {
	case AccessModeSubscription:
		return "subscription"
	case AccessModeSelfService:
		return "self-service"
	default:
		return ""
	}
}

func appendResourceNameSuffix(name, suffix string) string {
	name = strings.TrimSpace(name)
	suffix = strings.TrimSpace(suffix)
	if name == "" || suffix == "" {
		return name
	}
	if strings.HasSuffix(name, "-"+suffix) {
		return name
	}
	return name + "-" + suffix
}

func LatestModeAccessStatuses(ctx context.Context, store *sqlite.DB, batches []sqlite.ImportBatch) (ModeAccessStatuses, error) {
	var statuses ModeAccessStatuses
	for _, batch := range batches {
		if statuses.Subscription != "" && statuses.SelfService != "" {
			break
		}
		closures, err := store.AccessClosures().GetByBatchID(ctx, batch.ID)
		if err != nil {
			return ModeAccessStatuses{}, err
		}
		batchStatuses := modeAccessStatusesForBatch(batch, closures)
		if statuses.Subscription == "" && strings.TrimSpace(batchStatuses.Subscription) != "" {
			statuses.Subscription = strings.TrimSpace(batchStatuses.Subscription)
		}
		if statuses.SelfService == "" && strings.TrimSpace(batchStatuses.SelfService) != "" {
			statuses.SelfService = strings.TrimSpace(batchStatuses.SelfService)
		}
	}
	return statuses, nil
}

func modeAccessStatusesForBatch(batch sqlite.ImportBatch, closures []sqlite.AccessClosureRecord) ModeAccessStatuses {
	statuses := ModeAccessStatuses{}
	for _, closure := range closures {
		status := strings.TrimSpace(closure.Status)
		switch strings.TrimSpace(closure.ClosureType) {
		case AccessModeSubscription:
			statuses.Subscription = status
		case AccessModeSelfService:
			statuses.SelfService = status
		}
	}
	if statuses.Subscription == "" && statuses.SelfService == "" {
		return seedModeAccessStatuses(batch.AccessStatus)
	}
	return statuses
}

func seedModeAccessStatuses(accessStatus string) ModeAccessStatuses {
	switch strings.TrimSpace(accessStatus) {
	case AccessStatusFullyReady:
		return ModeAccessStatuses{Subscription: AccessStatusSubscriptionReady, SelfService: AccessStatusSelfServiceReady}
	case AccessStatusSubscriptionReady:
		return ModeAccessStatuses{Subscription: AccessStatusSubscriptionReady}
	case AccessStatusSelfServiceReady:
		return ModeAccessStatuses{SelfService: AccessStatusSelfServiceReady}
	default:
		return ModeAccessStatuses{}
	}
}

func AggregateAccessStatus(statuses ModeAccessStatuses) string {
	subscriptionReady := isReadyAccessStatus(statuses.Subscription, AccessModeSubscription)
	selfServiceReady := isReadyAccessStatus(statuses.SelfService, AccessModeSelfService)
	switch {
	case subscriptionReady && selfServiceReady:
		return AccessStatusFullyReady
	case subscriptionReady:
		return AccessStatusSubscriptionReady
	case selfServiceReady:
		return AccessStatusSelfServiceReady
	default:
		return AccessStatusBroken
	}
}

func isReadyAccessStatus(status, mode string) bool {
	status = strings.TrimSpace(status)
	switch mode {
	case AccessModeSubscription:
		return status == AccessStatusSubscriptionReady || status == AccessStatusFullyReady
	case AccessModeSelfService:
		return status == AccessStatusSelfServiceReady || status == AccessStatusFullyReady
	default:
		return status != "" && status != AccessStatusBroken
	}
}
