// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// +build !build_with_native_toolchain

package netstack

import (
	"context"
	"fmt"
	"sync"
	"syscall/zx/fidl"

	"go.fuchsia.dev/fuchsia/src/connectivity/network/netstack/dns"
	"go.fuchsia.dev/fuchsia/src/connectivity/network/netstack/fidlconv"
	"go.fuchsia.dev/fuchsia/src/lib/component"
	syslog "go.fuchsia.dev/fuchsia/src/lib/syslog/go"

	"fidl/fuchsia/net/name"
)

type dnsServerWatcher struct {
	parent *dnsServerWatcherCollection
	mu     struct {
		sync.Mutex
		isHanging    bool
		lastObserved []dns.Server
	}
}

var _ name.DnsServerWatcherWithCtx = (*dnsServerWatcher)(nil)

// serverListEquals compares if two slices of configured servers the same elements in the same
// order.
func serverListEquals(a []dns.Server, b []dns.Server) bool {
	if len(a) != len(b) {
		return false
	}
	for i := range a {
		if a[i] != b[i] {
			return false
		}
	}
	return true
}

func dnsServerToFidl(s dns.Server) name.DnsServer {
	var n name.DnsServer
	n.SetAddress(fidlconv.ToNetSocketAddress(s.Address))
	n.SetSource(s.Source)
	return n
}

func (w *dnsServerWatcher) WatchServers(ctx fidl.Context) ([]name.DnsServer, error) {
	w.mu.Lock()
	defer w.mu.Unlock()

	if w.mu.isHanging {
		return nil, fmt.Errorf("dnsServerWatcher: not allowed to watch twice")
	}

	for {
		servers, ch := w.parent.getServersCacheAndChannel()
		if !serverListEquals(servers, w.mu.lastObserved) {
			dnsServer := make([]name.DnsServer, 0, len(servers))
			for _, v := range servers {
				dnsServer = append(dnsServer, dnsServerToFidl(v))
			}
			// Store the last observed servers to compare in subsequent calls.
			w.mu.lastObserved = servers
			return dnsServer, nil
		}

		w.mu.isHanging = true

		w.mu.Unlock()

		var err error
		select {
		case <-ch:
		case <-ctx.Done():
			err = fmt.Errorf("context cancelled during hanging get: %w", ctx.Err())
		}
		w.mu.Lock()

		w.mu.isHanging = false

		if err != nil {
			return nil, err
		}
	}
}

type dnsServerWatcherCollection struct {
	getServersCacheAndChannel func() ([]dns.Server, <-chan struct{})
}

// newDnsServerWatcherCollection creates a new dnsServerWatcherCollection that will observe the
// server configuration provided by getServersCacheAndChannel.
func newDnsServerWatcherCollection(getServersCacheAndChannel func() ([]dns.Server, <-chan struct{})) *dnsServerWatcherCollection {
	collection := dnsServerWatcherCollection{
		getServersCacheAndChannel: getServersCacheAndChannel,
	}
	return &collection
}

// Bind binds a new fuchsia.net.name.DnsServerWatcher request to the collection of watchers and
// starts serving on its channel.
func (c *dnsServerWatcherCollection) Bind(request name.DnsServerWatcherWithCtxInterfaceRequest) error {
	go func() {
		watcher := dnsServerWatcher{
			parent: c,
		}

		stub := name.DnsServerWatcherWithCtxStub{
			Impl: &watcher,
		}
		component.ServeExclusive(context.Background(), &stub, request.Channel, func(err error) {
			// NB: this protocol is not discoverable, so the bindings do not include its name.
			_ = syslog.WarnTf("fuchsia.net.name.DnsServerWatcher", "%s", err)
		})
	}()

	return nil
}
