// Package agent provides a client for communicating with an "Agent"
// process holding the private key for an identity.
package agent

import (
	"fmt"
	"net"
	"os"

	"veyron.io/veyron/veyron/lib/unixfd"
	"veyron.io/veyron/veyron2/context"
	"veyron.io/veyron/veyron2/ipc"
	"veyron.io/veyron/veyron2/naming"
	"veyron.io/veyron/veyron2/security"
	"veyron.io/veyron/veyron2/vdl/vdlutil"
	"veyron.io/veyron/veyron2/vlog"
)

// FdVarName is the name of the environment variable containing
// the file descriptor for talking to the agent.
const FdVarName = "VEYRON_AGENT_FD"

type client struct {
	caller caller
	key    security.PublicKey
}

type caller struct {
	client ipc.Client
	name   string
	ctx    context.T
}

func (c *caller) call(name string, results []interface{}, args ...interface{}) (err error) {
	var call ipc.Call
	results = append(results, &err)
	if call, err = c.client.StartCall(c.ctx, c.name, name, args); err == nil {
		if ierr := call.Finish(results...); ierr != nil {
			err = ierr
		}
	}
	return
}

func results(inputs ...interface{}) []interface{} {
	if len(inputs) > 0 {
		return inputs
	}
	return make([]interface{}, 0)
}

// NewAgentPrincipal returns a security.Pricipal using the PrivateKey held in a remote agent process.
// 'fd' is the socket for connecting to the agent, typically obtained from
// os.GetEnv(agent.FdVarName).
// 'ctx' should not have a deadline, and should never be cancelled.
func NewAgentPrincipal(c ipc.Client, fd int, ctx context.T) (security.Principal, error) {
	conn, err := net.FileConn(os.NewFile(uintptr(fd), "agent_client"))
	if err != nil {
		return nil, err
	}
	// This is just an arbitrary 1 byte string. The value is ignored.
	data := make([]byte, 1)
	addr, err := unixfd.SendConnection(conn.(*net.UnixConn), data)
	if err != nil {
		return nil, err
	}
	caller := caller{
		client: c,
		name:   naming.JoinAddressName(naming.FormatEndpoint(addr.Network(), addr.String()), ""),
		ctx:    ctx,
	}

	agent := &client{caller: caller}
	if err := agent.fetchPublicKey(); err != nil {
		return nil, err
	}
	return agent, nil
}

func (c *client) fetchPublicKey() (err error) {
	var b []byte
	if err = c.caller.call("PublicKey", results(&b)); err != nil {
		return
	}
	c.key, err = security.UnmarshalPublicKey(b)
	return
}

func (c *client) Bless(key security.PublicKey, with security.Blessings, extension string, caveat security.Caveat, additionalCaveats ...security.Caveat) (security.Blessings, error) {
	var blessings security.WireBlessings
	marshalledKey, err := key.MarshalBinary()
	if err != nil {
		return nil, err
	}
	err = c.caller.call("Bless", results(&blessings), marshalledKey, security.MarshalBlessings(with), extension, caveat, additionalCaveats)
	if err != nil {
		return nil, err
	}
	return security.NewBlessings(blessings)
}

func (c *client) BlessSelf(name string, caveats ...security.Caveat) (security.Blessings, error) {
	var blessings security.WireBlessings
	err := c.caller.call("BlessSelf", results(&blessings), name, caveats)
	if err != nil {
		return nil, err
	}
	return security.NewBlessings(blessings)
}

func (c *client) Sign(message []byte) (sig security.Signature, err error) {
	err = c.caller.call("Sign", results(&sig), message)
	return
}

func (c *client) MintDischarge(tp security.ThirdPartyCaveat, caveat security.Caveat, additionalCaveats ...security.Caveat) (security.Discharge, error) {
	var discharge security.Discharge
	err := c.caller.call("MintDischarge", results(&discharge), vdlutil.Any(tp), caveat, additionalCaveats)
	if err != nil {
		return nil, err
	}
	return discharge, nil
}

func (c *client) PublicKey() security.PublicKey {
	return c.key
}

func (c *client) BlessingStore() security.BlessingStore {
	return &blessingStore{c.caller, c.key}
}

func (c *client) Roots() security.BlessingRoots {
	return &blessingRoots{c.caller}
}

func (c *client) AddToRoots(blessings security.Blessings) error {
	return c.caller.call("AddToRoots", results(), security.MarshalBlessings(blessings))
}

type blessingStore struct {
	caller caller
	key    security.PublicKey
}

func (b *blessingStore) Set(blessings security.Blessings, forPeers security.BlessingPattern) (security.Blessings, error) {
	var resultBlessings security.WireBlessings
	err := b.caller.call("BlessingStoreSet", results(&resultBlessings), security.MarshalBlessings(blessings), forPeers)
	if err != nil {
		return nil, err
	}
	return security.NewBlessings(resultBlessings)
}

func (b *blessingStore) ForPeer(peerBlessings ...string) security.Blessings {
	var resultBlessings security.WireBlessings
	err := b.caller.call("BlessingStoreForPeer", results(&resultBlessings), peerBlessings)
	if err != nil {
		vlog.Errorf("error calling BlessingStoreForPeer: %v", err)
		return nil
	}
	blessings, err := security.NewBlessings(resultBlessings)
	if err != nil {
		vlog.Errorf("error creating Blessings from WireBlessings: %v", err)
		return nil
	}
	return blessings
}

func (b *blessingStore) SetDefault(blessings security.Blessings) error {
	return b.caller.call("BlessingStoreSetDefault", results(), security.MarshalBlessings(blessings))
}

func (b *blessingStore) Default() security.Blessings {
	var resultBlessings security.WireBlessings
	err := b.caller.call("BlessingStoreDefault", results(&resultBlessings))
	if err != nil {
		vlog.Errorf("error calling BlessingStoreDefault: %v", err)
		return nil
	}
	blessings, err := security.NewBlessings(resultBlessings)
	if err != nil {
		vlog.Errorf("error creating Blessing from WireBlessings: %v", err)
		return nil
	}
	return blessings
}

func (b *blessingStore) PublicKey() security.PublicKey {
	return b.key
}

func (b *blessingStore) DebugString() (s string) {
	err := b.caller.call("BlessingStoreDebugString", results(&s))
	if err != nil {
		s = fmt.Sprintf("error calling BlessingStoreDebugString: %v", err)
		vlog.Errorf(s)
	}
	return
}

type blessingRoots struct {
	caller caller
}

func (b *blessingRoots) Add(root security.PublicKey, pattern security.BlessingPattern) error {
	marshalledKey, err := root.MarshalBinary()
	if err != nil {
		return err
	}
	return b.caller.call("BlessingRootsAdd", results(), marshalledKey, pattern)
}

func (b *blessingRoots) Recognized(root security.PublicKey, blessing string) error {
	marshalledKey, err := root.MarshalBinary()
	if err != nil {
		return err
	}
	return b.caller.call("BlessingRootsAdd", results(), marshalledKey, blessing)
}

func (b *blessingRoots) DebugString() (s string) {
	err := b.caller.call("BlessingRootsDebugString", results(&s))
	if err != nil {
		s = fmt.Sprintf("error calling BlessingRootsDebugString: %v", err)
		vlog.Errorf(s)
	}
	return
}
