package discovery

import (
	"context"
	"errors"
	"fmt"
	"log"
	"time"

	"github.com/nacos-group/nacos-sdk-go/v2/clients/naming_client"
	"github.com/nacos-group/nacos-sdk-go/v2/vo"
	"google.golang.org/grpc/resolver"
	"google.golang.org/grpc/serviceconfig"
)

type discoveryResolver struct {
	w  naming_client.INamingClient
	cc resolver.ClientConn

	ctx    context.Context
	cancel context.CancelFunc

	clusterName, serviceName, groupName string
}

func (r *discoveryResolver) watch() {
	for {
		select {
		case <-r.ctx.Done():
			return
		default:
		}

		svc, err := r.w.GetService(vo.GetServiceParam{
			ServiceName: r.serviceName,
			GroupName:   r.groupName,
			Clusters:    []string{r.clusterName},
		})
		if err != nil {
			time.Sleep(time.Second)
			continue
		}

		var addrs []resolver.Address
		for _, host := range svc.Hosts {
			if !host.Healthy || !host.Enable {
				continue
			}
			addrs = append(addrs, resolver.Address{
				Addr:       fmt.Sprintf("%s:%d", host.Ip, host.Port),
				ServerName: host.ServiceName,
			})
		}
		if len(addrs) > 0 {
			err = r.cc.UpdateState(resolver.State{
				Addresses: addrs,
			})
			if err != nil {
				log.Printf("[resolver] failed to update state: %s-%s-%v", r.serviceName, r.groupName, err)
			}
		} else {
			// fix: 没有发现可用服务的时候立马报错，无需等待超时
			err = r.cc.UpdateState(resolver.State{
				ServiceConfig: &serviceconfig.ParseResult{Err: errors.New(`service not found`)},
			})
			if err != nil {
				log.Printf("[resolver] failed to fetch available service: %s-%s-%v", r.serviceName, r.groupName, err)
			}
		}
		time.Sleep(time.Second * 10)
	}
}

func (r *discoveryResolver) Close() {
	r.cancel()
	r.w.Unsubscribe(&vo.SubscribeParam{
		ServiceName: r.serviceName,
		Clusters:    []string{r.clusterName},
		GroupName:   r.groupName,
	})
}

func (r *discoveryResolver) ResolveNow(_ resolver.ResolveNowOptions) {}
