package app

import (
	"context"
	"fmt"
	"net"
	"time"

	"dnsupdater/provider/manager"

	"dnsupdater/ip"
	"dnsupdater/ip/resolver"
)

// Constant name for the virtual WAN interface
const WAN_IFACE = "wan"

type App struct {
	cache *ip.Cache

	cacheDefaultCallback ip.CacheDefaultCallback

	// Updater manager
	ProviderManager *manager.Manager
}

func makeCacheCallback(service resolver.Service) ip.CacheDefaultCallback {
	return func(name string) (net.IP, error) {
		if name == WAN_IFACE {
			ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
			defer cancel()
			return service.Lookup(ctx)
		}
		return ip.GetInterfaceIP(name)
	}
}

func NewApp(config *Config) (*App, error) {
	providerMgr := manager.New()
	// providerMgr.Register("digitalocean", digitalocean.New(config.Services.DigitalOcean.Token))
	err := providerMgr.RegisterFromConfig(config.Providers)
	if err != nil {
		return nil, err
	}

	service := resolver.Get(config.Services.IPLookup)

	if service == nil {
		return nil, fmt.Errorf("Failed to load lookup service: %s", config.Services.IPLookup)
	}

	return &App{
		ProviderManager:      providerMgr,
		cache:                ip.NewCache(),
		cacheDefaultCallback: makeCacheCallback(service),
	}, nil
}

func (a App) GetIP(iface_name string) (net.IP, error) {
	return a.cache.GetWithDefault(iface_name, a.cacheDefaultCallback)
}
