package proxy_pool

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

	"kami/internal/model"
	"kami/utility/cache"

	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/net/gclient"
)

type ActiveExpireStrategy struct {
	cache            *cache.Cache
	apiURL           string
	ttl              time.Duration
	refreshThreshold time.Duration
	validator        *ProxyValidator
}

func NewActiveExpireStrategy(apiURL string, ttl time.Duration, refreshThreshold time.Duration) *ActiveExpireStrategy {
	if refreshThreshold >= ttl {
		refreshThreshold = ttl / 2
	}

	return &ActiveExpireStrategy{
		cache:            cache.NewCache(),
		apiURL:           apiURL,
		ttl:              ttl,
		refreshThreshold: refreshThreshold,
		validator:        NewProxyValidator(),
	}
}

func (s *ActiveExpireStrategy) GetProxy(ctx context.Context, orderId string) (*model.ProxyInfo, error) {
	key := cache.PrefixProxyPool.Key(orderId)

	result, err := s.cache.Get(ctx, key)
	if err != nil {
		return nil, gerror.Wrap(err, "获取代理缓存失败")
	}

	if result != nil && !result.IsNil() {
		var proxy model.ProxyInfo
		if err := json.Unmarshal(result.Bytes(), &proxy); err != nil {
			return nil, gerror.Wrap(err, "解析代理信息失败")
		}

		if !s.validator.ValidateProxy(ctx, &proxy) {
			_ = s.RemoveProxy(ctx, orderId)
			proxy, err := s.validator.GetValidProxy(ctx, s.fetchProxyFromAPI)
			if err != nil {
				return nil, err
			}
			_ = s.SetProxy(ctx, orderId, proxy)
			return proxy, nil
		}

		ttl, _ := s.cache.GetExpire(ctx, key)

		if ttl > 0 && ttl < s.refreshThreshold {
			go func() {
				newProxy, err := s.validator.GetValidProxy(context.Background(), s.fetchProxyFromAPI)
				if err == nil {
					_ = s.SetProxy(context.Background(), orderId, newProxy)
				}
			}()
		}

		return &proxy, nil
	}

	proxy, err := s.validator.GetValidProxy(ctx, s.fetchProxyFromAPI)
	if err != nil {
		return nil, err
	}

	if err := s.SetProxy(ctx, orderId, proxy); err != nil {
		return nil, err
	}

	return proxy, nil
}

func (s *ActiveExpireStrategy) SetProxy(ctx context.Context, orderId string, proxy *model.ProxyInfo) error {
	key := cache.PrefixProxyPool.Key(orderId)

	data, err := json.Marshal(proxy)
	if err != nil {
		return gerror.Wrap(err, "序列化代理信息失败")
	}

	if err := s.cache.Set(ctx, key, data, s.ttl); err != nil {
		return gerror.Wrap(err, "设置代理缓存失败")
	}

	return nil
}

func (s *ActiveExpireStrategy) RemoveProxy(ctx context.Context, orderId string) error {
	key := cache.PrefixProxyPool.Key(orderId)

	if _, err := s.cache.Remove(ctx, key); err != nil {
		return gerror.Wrap(err, "删除代理缓存失败")
	}

	return nil
}

func (s *ActiveExpireStrategy) GetTTL(ctx context.Context, orderId string) (time.Duration, error) {
	key := cache.PrefixProxyPool.Key(orderId)

	ttl, err := s.cache.GetExpire(ctx, key)
	if err != nil {
		return 0, gerror.Wrap(err, "获取代理过期时间失败")
	}

	return ttl, nil
}

func (s *ActiveExpireStrategy) fetchProxyFromAPI(ctx context.Context) (*model.ProxyInfo, error) {
	client := gclient.New()

	resp, err := client.Get(ctx, s.apiURL)
	if err != nil {
		return nil, gerror.Wrap(err, "调用代理API失败")
	}
	defer resp.Close()

	if resp.StatusCode != 200 {
		return nil, gerror.Newf("代理API返回异常状态码: %d", resp.StatusCode)
	}

	body := resp.ReadAllString()

	var proxy model.ProxyInfo
	if err := json.Unmarshal([]byte(body), &proxy); err != nil {
		return nil, gerror.Wrap(err, "解析代理API响应失败")
	}

	return &proxy, nil
}
