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

package global

import (
	"time"

	"v.io/v23"
	"v.io/v23/context"
	"v.io/v23/discovery"
	"v.io/v23/naming"
	"v.io/v23/security"
	"v.io/v23/security/access"
	idiscovery "v.io/x/ref/lib/discovery"
)

func (d *gdiscovery) Advertise(ctx *context.T, ad *discovery.Advertisement, visibility []security.BlessingPattern) (<-chan struct{}, error) {
	if !ad.Id.IsValid() {
		var err error
		if ad.Id, err = discovery.NewAdId(); err != nil {
			return nil, err
		}
	}
	if err := validateAd(ad); err != nil {
		return nil, idiscovery.NewErrBadAdvertisement(ctx, err)
	}
	if len(visibility) == 0 {
		visibility = []security.BlessingPattern{security.AllPrincipals}
	}

	principal := v23.GetPrincipal(ctx)
	self := security.DefaultBlessingPatterns(principal)
	perms := access.Permissions{
		string(access.Admin): access.AccessList{In: self},
		string(access.Read):  access.AccessList{In: visibility},
	}

	if !d.addAd(ad) {
		return nil, idiscovery.NewErrAlreadyBeingAdvertised(ctx, ad.Id)
	}

	// TODO(jhahn): There is no atomic way to check and reserve the name under mounttable.
	// For example, the name can be overwritten by other applications of the same owner.
	// But this would be OK for now.
	name, err := encodeAdToSuffix(ad, d.newAdTimestampNs())
	if err != nil {
		return nil, err
	}
	if err := d.ns.SetPermissions(ctx, name, perms, "", naming.IsLeaf(true)); err != nil {
		d.removeAd(ad)
		return nil, err
	}

	// TODO(jhahn): We're using one goroutine per advertisement, but we can do
	// better like have one goroutine that takes care of all advertisements.
	// But this is OK for now as an experiment.
	done := make(chan struct{})
	go func() {
		defer close(done)
		defer d.removeAd(ad)
		// We need a context that is detached from the deadlines and cancellation
		// of ctx since we have to unmount after ctx is canceled.
		rctx, rcancel := context.WithRootCancel(ctx)
		defer d.unmount(rctx, rcancel, name)

		for {
			d.mount(ctx, name, ad.Addresses)

			select {
			case <-d.clock.After(d.mountTTL):
			case <-ctx.Done():
				return
			}
		}
	}()
	return done, nil
}

func (d *gdiscovery) newAdTimestampNs() int64 {
	now := time.Now()
	timestampNs := now.UnixNano()
	d.mu.Lock()
	if d.adTimestampNs >= timestampNs {
		timestampNs = d.adTimestampNs + 1
	}
	d.adTimestampNs = timestampNs
	d.mu.Unlock()
	return timestampNs
}

func (d *gdiscovery) addAd(ad *discovery.Advertisement) bool {
	d.mu.Lock()
	if _, exist := d.ads[ad.Id]; exist {
		d.mu.Unlock()
		return false
	}
	d.ads[ad.Id] = struct{}{}
	d.mu.Unlock()
	return true
}

func (d *gdiscovery) removeAd(ad *discovery.Advertisement) {
	d.mu.Lock()
	delete(d.ads, ad.Id)
	d.mu.Unlock()
}

func (d *gdiscovery) mount(ctx *context.T, name string, addrs []string) {
	for _, addr := range addrs {
		if err := d.ns.Mount(ctx, name, addr, d.mountTTLWithSlack); err != nil {
			ctx.Errorf("mount(%q, %q) failed: %v", name, addr, err)
		}
	}
}

func (d *gdiscovery) unmount(ctx *context.T, cancel context.CancelFunc, name string) {
	if err := d.ns.Delete(ctx, name, true); err != nil {
		ctx.Infof("unmount(%q) failed: %v", name, err)
	}
	cancel()
}
