package mounttablelib

import (
	"strings"
	"sync"
	"time"

	"v.io/v23/context"

	"github.com/paypal/gatt"
	"github.com/paypal/gatt/linux/cmd"
)

var mounttableServiceUUID = gatt.MustParseUUID("f7d47ad1-c344-4ad1-b43a-5be7570d3ffd")
var addressesUUID = gatt.MustParseUUID("32719e70-5da5-4d40-9a4a-866f491b2f2d")

func newMountTableService(addresses []string) *gatt.Service {
	addressString := strings.Join(addresses, "@@@@")
	s := gatt.NewService(mounttableServiceUUID)
	s.AddCharacteristic(addressesUUID).HandleReadFunc(
		func(rsp gatt.ResponseWriter, req *gatt.ReadRequest) {
			if req.Offset > len(addressString) {
				return
			}
			end := req.Offset + req.Cap
			if end > len(addressString) {
				end = len(addressString)
			}
			rsp.Write([]byte(addressString[req.Offset:end]))
		})
	return s
}

var (
	attrGAPUUID = gatt.UUID16(0x1800)

	attrDeviceNameUUID        = gatt.UUID16(0x2A00)
	attrAppearanceUUID        = gatt.UUID16(0x2A01)
	attrPeripheralPrivacyUUID = gatt.UUID16(0x2A02)
	attrReconnectionAddrUUID  = gatt.UUID16(0x2A03)
	attrPeferredParamsUUID    = gatt.UUID16(0x2A04)

	attrGATTUUID           = gatt.UUID16(0x1801)
	attrServiceChangedUUID = gatt.UUID16(0x2A05)
)

// https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.gap.appearance.xml
var gapCharAppearanceGenericComputer = []byte{0x00, 0x80}

func newGapService(name string) *gatt.Service {
	s := gatt.NewService(attrGAPUUID)
	s.AddCharacteristic(attrDeviceNameUUID).SetValue([]byte(name))
	s.AddCharacteristic(attrAppearanceUUID).SetValue(gapCharAppearanceGenericComputer)
	s.AddCharacteristic(attrPeripheralPrivacyUUID).SetValue([]byte{0x00})
	s.AddCharacteristic(attrReconnectionAddrUUID).SetValue([]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00})
	s.AddCharacteristic(attrPeferredParamsUUID).SetValue([]byte{0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0xd0, 0x07})
	return s
}

func newGattService() *gatt.Service {
	s := gatt.NewService(attrGATTUUID)
	s.AddCharacteristic(attrServiceChangedUUID).HandleNotifyFunc(
		func(r gatt.Request, n gatt.Notifier) {})
	return s
}

var gattServerOptions = []gatt.Option{
	gatt.LnxMaxConnections(100),
	gatt.LnxDeviceID(-1, true),
	gatt.LnxSetAdvertisingParameters(&cmd.LESetAdvertisingParameters{
		// Set an advertising rate of 150ms.  This value is multipled by
		// 0.625ms to get the actual rate.
		AdvertisingIntervalMin: 0x00f4,
		AdvertisingIntervalMax: 0x00f4,
		AdvertisingChannelMap:  0x7,
	}),
}

type bleCacheEntry struct {
	id        string
	name      string
	endpoints []string
	lastSeen  time.Time
}
type bleNeighborHood struct {
	mu                 sync.Mutex
	neighborsIdCache   map[string]*bleCacheEntry
	neighborsNameCache map[string]*bleCacheEntry
	name               string
	ctx                *context.T
	serverDevice       gatt.Device
	clientDevice       gatt.Device
}

func newBleNeighborhood(ctx *context.T, name string, eps []string) (*bleNeighborHood, error) {
	b := &bleNeighborHood{
		neighborsIdCache:   make(map[string]*bleCacheEntry),
		neighborsNameCache: make(map[string]*bleCacheEntry),
		name:               name,
		ctx:                ctx,
	}
	return b, b.startBLEService(eps)
}

func (b *bleNeighborHood) startBLEService(eps []string) error {
	d, err := gatt.NewDevice(gattServerOptions...)
	if err != nil {
		return err
	}
	d.Handle(
		gatt.CentralConnected(func(c gatt.Central) { b.ctx.VI(0).Infof("Connect: %v", c.ID()) }),
		gatt.CentralDisconnected(func(c gatt.Central) { b.ctx.VI(0).Infof("Disconnected: %v", c.ID()) }),
	)

	onStateChanged := func(d gatt.Device, s gatt.State) {
		b.ctx.VI(0).Infof("State: %s", s)
		switch s {
		case gatt.StatePoweredOn:
			d.AddService(newGapService(b.name))
			d.AddService(newGattService())

			s1 := newMountTableService(eps)
			d.AddService(s1)
			d.AdvertiseNameAndServices(b.name, []gatt.UUID{s1.UUID()})
		default:
		}
	}

	d.Init(onStateChanged)
	b.serverDevice = d
	return nil
}

var gattClientOptions = []gatt.Option{
	gatt.LnxMaxConnections(1),
	gatt.LnxDeviceID(-1, true),
}

func (b *bleNeighborHood) scanForNeighbors() {
	onStateChanged := func(d gatt.Device, s gatt.State) {
		switch s {
		case gatt.StatePoweredOn:
			// We should limit it to only mounttable service, but this
			// isn't implemented in the library
			d.Scan([]gatt.UUID{}, false)
		default:
			d.StopScanning()
		}
	}

	onPeriphDiscovered := func(p gatt.Peripheral, a *gatt.Advertisement, rssi int) {
		// TODO(bjornick): Handle error
		p.Device().Connect(p)
	}

	onPeriphConnected := func(p gatt.Peripheral, err error) {
		defer p.Device().CancelConnection(p)
		if err := p.SetMTU(500); err != nil {
			b.ctx.Errorf("Failed to set MTU, err: %s", err)
			return
		}

		ss, err := p.DiscoverServices(nil)

		if err != nil {
			b.ctx.Errorf("Failed to discover services, err: %s", err)
			return
		}

		for _, s := range ss {
			if !s.UUID().Equal(mounttableServiceUUID) {
				b.ctx.Infof("Skipping non-mt service %s", s.Name())
				continue
			}

			cs, err := p.DiscoverCharacteristics(nil, s)
			if err != nil {
				b.ctx.Errorf("Failed to discover characteristics: %s", err)
				continue
			}

			for _, c := range cs {
				if !c.UUID().Equal(addressesUUID) {
					b.ctx.Infof("Skipping non-address characteristic: %s", c.Name())
					continue
				}
				eps, err := p.ReadCharacteristicBlob(c)
				if err != nil {
					b.ctx.Errorf("Failed to read the addresses: %v", err)
					continue
				}
				b.saveAddress(p.ID(), p.Name(), string(eps))
			}

		}
	}
	var err error
	b.clientDevice, err = gatt.NewDevice(gattClientOptions...)
	if err != nil {
		b.ctx.Errorf("Failed to open device, err: %s\n", err)
		return
	}
	b.clientDevice.Handle(
		gatt.PeripheralDiscovered(onPeriphDiscovered),
		gatt.PeripheralConnected(onPeriphConnected),
	)

	b.clientDevice.Init(onStateChanged)
}

func (b *bleNeighborHood) saveAddress(id string, name string, eps string) {
	b.mu.Lock()
	defer b.mu.Unlock()
	b.ctx.VI(0).Infof("Saving endpoints (%s) for (%s, %s)", eps, id, name)
	entry, found := b.neighborsIdCache[id]
	if !found {
		entry = &bleCacheEntry{
			id:   id,
			name: name,
		}
		b.neighborsIdCache[id] = entry
		b.neighborsNameCache[name] = entry
	}

	if entry.name != name {
		b.ctx.Errorf("Name of the neighbor changed. was %s, now %s", entry.name, name)
		return
	}
	entry.endpoints = strings.Split(eps, "@@@")
	entry.lastSeen = time.Now()
}
