// Copyright Daytona Platforms Inc.
// SPDX-License-Identifier: AGPL-3.0

package config

import (
	"context"
	"time"

	common_cache "github.com/daytonaio/common-go/pkg/cache"
	apiclient "github.com/daytonaio/daytona/libs/api-client-go"
	"go.uber.org/zap"
)

// Resolver handles retrieving and caching endpoint configurations.
type Resolver struct {
	cache     common_cache.ICache[apiclient.OtelConfig]
	logger    *zap.Logger
	apiclient *apiclient.APIClient
	cacheTTL  time.Duration
}

// NewResolver creates a new configuration resolver.
func NewResolver(cache common_cache.ICache[apiclient.OtelConfig], logger *zap.Logger, apiClient *apiclient.APIClient, cacheTTL time.Duration) *Resolver {
	return &Resolver{
		cache:     cache,
		logger:    logger,
		apiclient: apiClient,
		cacheTTL:  cacheTTL,
	}
}

func (r *Resolver) GetOrganizationOtelConfig(ctx context.Context, authToken string) (*apiclient.OtelConfig, error) {
	otelConfig, err := r.cache.Get(ctx, authToken)
	if err == nil {
		if otelConfig.Endpoint == "(none)" {
			return nil, nil
		}
		return otelConfig, nil
	}

	otelConfig, res, err := r.apiclient.OrganizationsAPI.GetOrganizationOtelConfigBySandboxAuthToken(context.Background(), authToken).Execute()
	if err != nil && res != nil && res.StatusCode != 404 {
		return nil, err
	}

	// Store this in cache to prevent repeated api calls for orgs that don't have otel endpoints
	config := &apiclient.OtelConfig{
		Endpoint: "(none)",
	}

	if otelConfig != nil {
		config = &apiclient.OtelConfig{
			Endpoint: otelConfig.Endpoint,
			Headers:  otelConfig.Headers,
		}
	}

	if err := r.cache.Set(ctx, authToken, *config, r.cacheTTL); err != nil {
		return nil, err
	}

	if config.Endpoint == "(none)" {
		return nil, nil
	}

	return config, nil
}

func (r *Resolver) GetOrganizationOtelConfigByOrgId(ctx context.Context, orgId string) (*apiclient.OtelConfig, error) {
	cacheKey := "org:" + orgId
	otelConfig, err := r.cache.Get(ctx, cacheKey)
	if err == nil {
		if otelConfig.Endpoint == "(none)" {
			return nil, nil
		}
		return otelConfig, nil
	}

	otelConfig, res, err := r.apiclient.OrganizationsAPI.GetOrganizationOtelConfig(ctx, orgId).Execute()
	if err != nil && res != nil && res.StatusCode != 404 {
		return nil, err
	}

	config := &apiclient.OtelConfig{
		Endpoint: "(none)",
	}

	if otelConfig != nil {
		config = &apiclient.OtelConfig{
			Endpoint: otelConfig.Endpoint,
			Headers:  otelConfig.Headers,
		}
	}

	if err := r.cache.Set(ctx, cacheKey, *config, r.cacheTTL); err != nil {
		return nil, err
	}

	if config.Endpoint == "(none)" {
		return nil, nil
	}

	return config, nil
}

// InvalidateCache removes a specific sandbox configuration from the cache.
func (r *Resolver) InvalidateCache(ctx context.Context, sandboxID string) error {
	return r.cache.Delete(ctx, sandboxID)
}
