package main

import (
	"log"
	"sync"

	"v.io/v23"
	"v.io/v23/context"
	"v.io/v23/discovery"
	"v.io/v23/verror"
	idiscovery "v.io/x/ref/lib/discovery"
	"v.io/x/ref/lib/discovery/plugins/ble"
	"v.io/x/ref/lib/discovery/plugins/mdns"

	_ "v.io/x/ref/runtime/factories/generic"

	mojom "mojom/vanadium/discovery"

	"mojo/public/go/application"
	"mojo/public/go/bindings"
	"mojo/public/go/system"
)

//#include "mojo/public/c/system/types.h"
import "C"

type discoveryService struct {
	mu           sync.Mutex
	ctx          *context.T
	s            discovery.T
	trigger      *idiscovery.Trigger
	nextAdv      int32
	pendingAdvs  map[int32]chan struct{}
	nextScan     int32
	pendingScans map[int32]chan struct{}
}

func convertToErrorStruct(err error) *mojom.Error {
	outErr := &mojom.Error{
		Id:  "v.io/verror/Unknown",
		Msg: err.Error(),
	}
	if e, ok := err.(verror.E); ok {
		outErr.Id = string(e.ID)
		outErr.Action = int32(e.Action)
	}
	return outErr
}

func (d *discoveryService) Advertise(s mojom.Service, patterns []string) (int32, *mojom.Error, error) {
	vService := discovery.Service{
		InstanceUuid:  s.InstanceUuid,
		InterfaceName: s.InterfaceName,
		Attrs:         discovery.Attributes(s.Attrs),
		Addrs:         s.Addrs,
	}

	ctx, c := context.WithCancel(d.ctx)

	err := d.s.Advertise(ctx, vService, nil)
	if err != nil {
		return 0, convertToErrorStruct(err), nil
	}
	ch := make(chan struct{})
	d.mu.Lock()
	id := d.nextAdv
	d.pendingAdvs[id] = ch
	d.nextAdv++
	d.mu.Unlock()
	d.trigger.Add(c, ch)
	return id, nil, nil
}

func (d *discoveryService) StopAdvertising(handle int32) error {
	d.mu.Lock()
	ch := d.pendingAdvs[handle]
	d.mu.Unlock()
	if ch != nil {
		close(ch)
	}
	return nil
}

func vServiceTomService(s discovery.Service) mojom.Service {
	return mojom.Service{
		InstanceUuid:  s.InstanceUuid,
		InterfaceName: s.InterfaceName,
		Attrs:         s.Attrs,
		Addrs:         s.Addrs,
	}
}

func (d *discoveryService) Scan(query string, scanHandler mojom.ScanHandler_Pointer) (int32, *mojom.Error, error) {
	ctx, c := context.WithCancel(d.ctx)
	proxy := mojom.NewScanHandlerProxy(scanHandler, bindings.GetAsyncWaiter())
	scanCh, err := d.s.Scan(ctx, query)
	if err != nil {
		return 0, convertToErrorStruct(err), nil
	}
	ch := make(chan struct{})
	d.mu.Lock()
	id := d.nextScan
	d.pendingScans[id] = ch
	d.nextScan++
	d.mu.Unlock()

	d.trigger.Add(c, ch)
	go func() {
		for v := range scanCh {
			log.Println("got value from chan", v)
			switch value := v.Interface().(type) {
			case discovery.UpdateFound:
				proxy.Found(vServiceTomService(value.Value.Service))
			case discovery.UpdateLost:
				proxy.Lost(vServiceTomService(value.Value.Service))
			}
		}
	}()
	return id, nil, nil
}

func (d *discoveryService) StopScan(handle int32) error {
	d.mu.Lock()
	ch := d.pendingScans[handle]
	d.mu.Unlock()
	if ch != nil {
		close(ch)
	}
	return nil
}

func (d *discoveryService) stop() {
	d.mu.Lock()
	for _, ch := range d.pendingScans {
		close(ch)
	}

	for _, ch := range d.pendingAdvs {
		close(ch)
	}
	d.mu.Unlock()
}

type discoveryDelegate struct {
	stubs    []*bindings.Stub
	impl     *discoveryService
	shutdown v23.Shutdown
}

func (d *discoveryDelegate) Initialize(c application.Context) {
	ctx, shutdown := v23.Init()
	host := c.Args()[1]
	log.Println("Starting discovery with name", host)
	mplugin, err := mdns.New(host)
	if err != nil {
		log.Println("Failed to start mplugin", err)
	}

	bplugin, err := ble.NewPlugin(host)
	if err != nil {
		log.Println("Failed to start bplugin", err)
	}

	d.impl = &discoveryService{
		ctx:          ctx,
		trigger:      idiscovery.NewTrigger(),
		s:            idiscovery.New([]idiscovery.Plugin{mplugin, bplugin}),
		pendingAdvs:  map[int32]chan struct{}{},
		pendingScans: map[int32]chan struct{}{},
	}
	d.shutdown = shutdown
}

func (d *discoveryDelegate) Create(request mojom.Discoverer_Request) {
	stub := mojom.NewDiscovererStub(request, d.impl, bindings.GetAsyncWaiter())
	d.stubs = append(d.stubs, stub)
	go func() {
		for {
			if err := stub.ServeRequest(); err != nil {
				connectionErr, ok := err.(*bindings.ConnectionError)
				if !ok || !connectionErr.Closed() {
					log.Println(err)
				}
				break
			}
		}
	}()
}

func (d *discoveryDelegate) AcceptConnection(connection *application.Connection) {
	connection.ProvideServices(&mojom.Discoverer_ServiceFactory{d})
}

func (d *discoveryDelegate) Quit() {
	d.impl.stop()
	d.shutdown()
	for _, stub := range d.stubs {
		stub.Close()
	}
}

//export MojoMain
func MojoMain(handle C.MojoHandle) C.MojoResult {
	application.Run(&discoveryDelegate{}, system.MojoHandle(handle))
	return C.MOJO_RESULT_OK
}

func main() {
}
