// 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 bridge

import (
	"v.io/v23"
	"v.io/v23/context"
	"v.io/v23/naming"
	"v.io/v23/rpc"
	"v.io/v23/security"
	wire "v.io/v23/services/syncbase"
	"v.io/v23/verror"
	"v.io/v23/vtrace"
)

// Bridge object, representing an in-process Syncbase singleton.
type Bridge struct {
	Ctx      *context.T
	Shutdown context.CancelFunc
	srv      rpc.Server
	disp     rpc.Dispatcher
	Cleanup  func()
}

func NewBridge(ctx *context.T, shutdown context.CancelFunc, srv rpc.Server, disp rpc.Dispatcher, cleanup func()) *Bridge {
	return &Bridge{Ctx: ctx, Shutdown: shutdown, srv: srv, disp: disp, Cleanup: cleanup}
}

func (b *Bridge) NewCtxCall(suffix string, method rpc.MethodDesc) (*context.T, rpc.ServerCall) {
	ctx, _ := vtrace.WithNewTrace(b.Ctx)
	return ctx, newFakeServerCall(ctx, b.srv, suffix, method)
}

func (b *Bridge) Destroy() {
	b.Cleanup()
	b.Shutdown()
}

////////////////////////////////////////
// Dispatch-related methods

func (b *Bridge) lookupAndAuthorize(ctx *context.T, call rpc.ServerCall, suffix string) (interface{}, error) {
	resInt, auth, err := b.disp.Lookup(ctx, suffix)
	if err != nil {
		return nil, err
	}
	if err := auth.Authorize(ctx, call.Security()); err != nil {
		return nil, verror.New(verror.ErrNoAccess, ctx, err)
	}
	return resInt, nil
}

func (b *Bridge) GetService(ctx *context.T, call rpc.ServerCall) (wire.ServiceServerStubMethods, error) {
	resInt, err := b.lookupAndAuthorize(ctx, call, "")
	if err != nil {
		return nil, err
	}
	if res, ok := resInt.(wire.ServiceServerStubMethods); !ok {
		return nil, verror.NewErrInternal(ctx)
	} else {
		return res, nil
	}
}

func (b *Bridge) GetDb(ctx *context.T, call rpc.ServerCall, name string) (wire.DatabaseServerStubMethods, error) {
	resInt, err := b.lookupAndAuthorize(ctx, call, name)
	if err != nil {
		return nil, err
	}
	if res, ok := resInt.(wire.DatabaseServerStubMethods); !ok {
		return nil, verror.NewErrInternal(ctx)
	} else {
		return res, nil
	}
}

func (b *Bridge) GetGlobber(ctx *context.T, call rpc.ServerCall, name string) (rpc.ChildrenGlobber, error) {
	resInt, err := b.lookupAndAuthorize(ctx, call, name)
	if err != nil {
		return nil, err
	}
	if res, ok := resInt.(rpc.Globber); !ok {
		return nil, verror.NewErrInternal(ctx)
	} else if res.Globber() == nil || res.Globber().ChildrenGlobber == nil {
		return nil, verror.NewErrInternal(ctx)
	} else {
		return res.Globber().ChildrenGlobber, nil
	}
}

func (b *Bridge) GetCollection(ctx *context.T, call rpc.ServerCall, name string) (wire.CollectionServerStubMethods, error) {
	resInt, err := b.lookupAndAuthorize(ctx, call, name)
	if err != nil {
		return nil, err
	}
	if res, ok := resInt.(wire.CollectionServerStubMethods); !ok {
		return nil, verror.NewErrInternal(ctx)
	} else {
		return res, nil
	}
}

func (b *Bridge) GetRow(ctx *context.T, call rpc.ServerCall, name string) (wire.RowServerStubMethods, error) {
	resInt, err := b.lookupAndAuthorize(ctx, call, name)
	if err != nil {
		return nil, err
	}
	if res, ok := resInt.(wire.RowServerStubMethods); !ok {
		return nil, verror.NewErrInternal(ctx)
	} else {
		return res, nil
	}
}

////////////////////////////////////////
// fakeServerCall

type fakeServerCall struct {
	sec    security.Call
	srv    rpc.Server
	suffix string
}

// TODO(sadovsky): Synthesize endpoints and discharges as needed.
func newFakeServerCall(ctx *context.T, srv rpc.Server, suffix string, method rpc.MethodDesc) rpc.ServerCall {
	p := v23.GetPrincipal(ctx)
	// HACK: For now, we set the "remote" (client, i.e. mobile app) blessing to be
	// the same as the "local" (server, i.e. Syncbase module) blessing.
	// TODO(sadovsky): Eliminate this hack.
	blessings, _ := p.BlessingStore().Default()
	return &fakeServerCall{
		sec: security.NewCall(&security.CallParams{
			Method:          method.Name,
			MethodTags:      method.Tags,
			Suffix:          suffix,
			LocalPrincipal:  p,
			LocalBlessings:  blessings,
			RemoteBlessings: blessings,
		}),
		srv:    srv,
		suffix: suffix,
	}
}

var _ rpc.ServerCall = (*fakeServerCall)(nil)

func (call *fakeServerCall) Security() security.Call {
	return call.sec
}

func (call *fakeServerCall) Suffix() string {
	return call.suffix
}

func (call *fakeServerCall) LocalEndpoint() naming.Endpoint {
	return call.sec.LocalEndpoint()
}

func (call *fakeServerCall) RemoteEndpoint() naming.Endpoint {
	return call.sec.RemoteEndpoint()
}

func (call *fakeServerCall) GrantedBlessings() security.Blessings {
	return security.Blessings{}
}

func (call *fakeServerCall) Server() rpc.Server {
	return call.srv
}
