package digitalocean

import (
	"context"
	"errors"
	"fmt"
	"net"

	"dnsupdater/provider"

	"github.com/digitalocean/godo"
)

type Provider struct {
	service godo.DomainsService
	cache   map[string][]godo.DomainRecord
}

func New(token string) Provider {
	return Provider{
		service: godo.NewFromToken(token).Domains,
		cache:   make(map[string][]godo.DomainRecord),
	}
}

func Factory(args map[string]interface{}) (provider.Provider, error) {
	t, ok := args["token"]
	if !ok {
		return nil, errors.New("did not find token")
	}

	token, ok := t.(string)
	if !ok {
		return nil, errors.New("token must be a string")
	}

	return New(token), nil
}

func (d *Provider) fetch(domain string) ([]godo.DomainRecord, error) {
	domains, ok := d.cache[domain]
	if !ok {
		var err error
		options := &godo.ListOptions{
			PerPage: 50,
		}

		domains, _, err = d.service.RecordsByType(context.Background(), domain, "A", options)
		if err != nil {
			return nil, err
		}
		d.cache[domain] = domains
	}
	return domains, nil
}

func (d *Provider) find(domain string, record string) (*godo.DomainRecord, error) {
	records, err := d.fetch(domain)
	if err != nil {
		return nil, err
	}
	for _, r := range records {
		if r.Name == record {
			return &r, nil
		}
	}

	return nil, fmt.Errorf("could not find record %s", record)
}

func (d Provider) Update(domain string, record string, ip net.IP) error {
	r, err := d.find(domain, record)
	if err != nil {
		return err
	}

	if r.Data != ip.String() {
		// Update
		req := godo.DomainRecordEditRequest{
			// Type:     r.Type,
			// Name:     r.Name,
			Data: ip.String(),
			// Priority: r.Priority,
			// Port:     r.Port,
			// TTL:      r.TTL,
			// Weight:   r.Weight,
			// Flags:    r.Flags,
			// Tag:      r.Tag,
		}

		_, _, err := d.service.EditRecord(context.Background(), domain, r.ID, &req)
		if err != nil {
			return err
		}
	}

	return nil
}
