package restriction

import (
	"context"
	"errors"

	"github.com/duke-git/lancet/v2/random"
	"github.com/duke-git/lancet/v2/retry"
	"github.com/gogf/gf/v2/util/gconv"
	"golang.org/x/exp/maps"
)

type Location interface {
	QueryLocationByIP(ctx context.Context, ip string) (Response, error)
}

var implementations = map[ConstsImpl]func() Location{
	CSDNImpl:     func() Location { return &CSDNClient{} },
	PCOnlineImpl: func() Location { return &PcOnlineClient{} },
	OlToolsImpl:  func() Location { return &OlToolsClient{} },
	IdCdImpl:     func() Location { return &IdCdClient{} },
	MeiTuImpl:    func() Location { return &MeiTuClient{} },
	VoImpl:       func() Location { return &VoClient{} },
	DBIPImpl:     func() Location { return &DBIPClient{} },
	QJQQImpl:     func() Location { return &QJQQClient{} },
	IQIYIImpl:    func() Location { return &IQIYIClient{} },
	IP66nImpl:    func() Location { return &IP66Client{} },
}

func GetLocationByIP(ctx context.Context, ip string) (resp Response, err error) {
	err = retry.Retry(func() error {
		resp, err = implementations[random.RandFromGivenSlice(maps.Keys(implementations))]().QueryLocationByIP(ctx, ip)
		if resp.City == "" {
			err = errors.New("ip location not found")
		}
		return err
	}, retry.RetryTimes(gconv.Uint(len(implementations))), retry.Context(ctx))
	return
}
