package elasticache

import (
	"context"
	"fmt"
	"time"

	log "github.com/Sirupsen/logrus"
)

// ServerList is implemented by memcache.ServerList
type ServerList interface {
	SetServers(servers ...string) error
}

// Poller polls the ElastiCache endpoint every minute to update the server list.
// Use NewPoller to construct a configured poller.
type Poller struct {
	endpoint   string
	serverList ServerList
	conn       *conn
}

// NewPoller constructs a configured poller.
func NewPoller(endpoint string, sl ServerList) *Poller {
	return &Poller{
		endpoint:   endpoint,
		serverList: sl,
	}
}

// Start starts a goroutine that polls the ElastiCache endpoint and reconnects if necessary.
// Cancelling the provided context will stop the background goroutine.
func (p *Poller) Start(ctx context.Context) error {

	c, err := connect(p.endpoint)
	if err != nil {
		return err
	}

	// TODO: reconnect if the connection is closed

	if err := p.pollNow(c); err != nil {
		return err
	}

	go func(ctx context.Context) {
		defer c.Close()

		select {
		case <-ctx.Done():
			return
		case <-time.After(time.Minute):
			if err := p.pollNow(c); err != nil {
				log.Error(err)
			}
		}
	}(ctx)

	return nil
}

func (p *Poller) pollNow(c *conn) error {
	cfg, err := getConfig(c.rw)
	if err != nil {
		return err
	}
	servers := make([]string, len(cfg.nodes))
	for i, n := range cfg.nodes {
		servers[i] = fmt.Sprintf("%s:%s", n.ip, n.port)
	}
	if err = p.serverList.SetServers(servers...); err != nil {
		return err
	}
	return nil
}
