// 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 ble implements a ble protocol to support the Vanadium discovery api.
// The package exports a discovery.Plugin that can be used to use ble for discovery.
// The advertising packet of Vanadium device should contain a manufacturer data field
// with the manufacturer id of 1001.  The first 8 bytes of the data is the hash of
// the services exported.  If the hash has not changed, then it is expected that the
// services and the properties they contain has not changed either.
package ble

import (
	"encoding/hex"
	"hash/fnv"
	"log"
	"reflect"
	"strings"
	"sync"
	"time"

	"github.com/paypal/gatt"
	"github.com/pborman/uuid"
	"v.io/x/ref/lib/discovery"
)

const (
	// TODO(bjornick): Make sure this is actually unique.
	manufacturerId = uint16(1001)
	ttl            = time.Minute * 5
)

var (
	// These constants are taken from:
	// https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicsHome.aspx
	attrGAPUUID  = gatt.UUID16(0x1800)
	attrGATTUUID = gatt.UUID16(0x1801)
)

func newV23Service(uuid uuid.UUID, attrs map[string][]byte) *gatt.Service {
	s := gatt.NewService(gatt.MustParseUUID(uuid.String()))
	for k, v := range attrs {
		s.AddCharacteristic(gatt.MustParseUUID(k)).SetValue(v)
	}
	return s
}

type bleCacheEntry struct {
	id             string
	advertisements map[string]*bleAdv
	hash           string
	lastSeen       time.Time
}

type bleNeighborhood struct {
	mu sync.Mutex

	// key is the hex encoded hash of the bleCacheEntry
	neighborsHashCache map[string]*bleCacheEntry
	// key is the hex encoded ID of the device.
	knownNeighbors map[string]*bleCacheEntry
	// key is the hex-encoded instance id
	services map[string]*gatt.Service
	// Scanners out standing calls to Scan that need be serviced.  Each time a
	// new device appears or disappears, the scanner is notified of the event.
	// The key is the unique scanner id for the scanner.
	scannersById map[int64]*scanner

	// scannersByService maps from human readable service uuid to a map of
	// scanner id to scanner.
	scannersByService map[string]map[int64]*scanner

	// If both sides try to connect to each other at the same time, then only
	// one will succeed and the other hangs forever.  This means that the side
	// that hangs won't ever start scanning or advertising again.  To avoid this
	// we timeout any connections that don't finish in under 4 seconds.  This
	// channel is closed when a connection has been made successfully, to notify
	// the cancel goroutine that it doesn't need to do anything.  This is a map
	// from the hex encoded device id to the channel to close.
	timeoutMap map[string]chan struct{}

	// The hash that we use to avoid multiple connections are stored in the
	// advertising data, so we need to store somewhere in the bleNeighorhood
	// until we are ready to save the new device data.  This map is
	// the keeper of the data.  This is a map from hex encoded device id to
	// hex encoded hash.
	pendingHashMap map[string]string
	name           string
	device         gatt.Device
	stopped        chan struct{}
	nextScanId     int64
}

func newBleNeighborhood(name string) (*bleNeighborhood, error) {
	b := &bleNeighborhood{
		neighborsHashCache: make(map[string]*bleCacheEntry),
		knownNeighbors:     make(map[string]*bleCacheEntry),
		name:               name,
		services:           make(map[string]*gatt.Service),
		scannersById:       make(map[int64]*scanner),
		scannersByService:  make(map[string]map[int64]*scanner),
		timeoutMap:         make(map[string]chan struct{}),
		pendingHashMap:     make(map[string]string),
		stopped:            make(chan struct{}),
	}
	if err := b.startBLEService(); err != nil {
		return nil, err
	}

	go b.checkTTL()
	return b, nil
}

func (b *bleNeighborhood) checkTTL() {
	for {
		select {
		case <-b.stopped:
			return
		case <-time.After(time.Minute):
			b.mu.Lock()
			now := time.Now()

			for k, entry := range b.neighborsHashCache {
				if entry.lastSeen.Add(ttl).Before(now) {
					delete(b.neighborsHashCache, k)
					delete(b.knownNeighbors, entry.id)
					for id, adv := range entry.advertisements {
						for _, scanner := range b.scannersById {
							scanner.handleChange(uuid.Parse(id), adv, nil)
						}
					}
				}
			}
			b.mu.Unlock()
		}
	}
}

func (b *bleNeighborhood) addAdvertisement(adv bleAdv) {
	b.mu.Lock()
	b.services[hex.EncodeToString(adv.instanceID)] = newV23Service(adv.serviceUUID, adv.attrs)
	v := make([]*gatt.Service, len(b.services))
	i := 0
	for _, s := range b.services {
		v[i] = s
		i++
	}
	b.mu.Unlock()
	b.device.SetServices(v)
}

func (b *bleNeighborhood) removeService(id []byte) {
	b.mu.Lock()
	delete(b.services, hex.EncodeToString(id))
	v := make([]*gatt.Service, 0, len(b.services))
	for _, s := range b.services {
		v = append(v, s)
	}
	b.mu.Unlock()
	b.device.SetServices(v)
}

func (b *bleNeighborhood) addScanner(uid discovery.Uuid) (chan *discovery.Advertisement, int64) {
	ch := make(chan *discovery.Advertisement)
	s := &scanner{
		uuid: uuid.UUID(uid),
		ch:   ch,
	}
	b.mu.Lock()
	id := b.nextScanId
	b.nextScanId++
	b.scannersById[id] = s
	key := uuid.UUID(uid).String()
	m, found := b.scannersByService[key]
	if !found {
		m = map[int64]*scanner{}
		b.scannersByService[key] = m
	}
	m[id] = s
	b.mu.Unlock()
	return ch, id
}

func (b *bleNeighborhood) removeScanner(id int64) {
	b.mu.Lock()
	scanner, found := b.scannersById[id]
	if found {
		scanner.stop()
	}
	delete(b.scannersById, id)
	key := scanner.uuid.String()
	delete(b.scannersByService[key], id)
	b.mu.Unlock()
}

func (b *bleNeighborhood) Stop() error {
	close(b.stopped)
	b.device.StopAdvertising()
	b.device.StopScanning()
	return nil
}

func (b *bleNeighborhood) advertiseAndScan() {
	select {
	case <-b.stopped:
		return
	default:
	}

	b.device.Advertise(b.computeAdvertisement())
	b.mu.Lock()
	hasScanner := len(b.scannersById) > 0
	b.mu.Unlock()
	// TODO(bjornick): Don't scan unless there is a scanner running.
	if hasScanner {
		b.device.Scan([]gatt.UUID{}, true)
	}
}

// seenHash returns whether or not we have seen the hash <h> before.
func (b *bleNeighborhood) seenHash(id string, h []byte) bool {
	b.mu.Lock()
	defer b.mu.Unlock()
	key := hex.EncodeToString(h)
	entry, ok := b.neighborsHashCache[key]
	if !ok {
		b.pendingHashMap[id] = key
		return false
	}

	if entry.id != id {
		// This can happen either because two different devices chose the same
		// endpoint and name, or that one device changed its mac address.  It
		// seems more likely that the latter happened
		// TODO(bjornick): Deal with the first case.
		entry.id = id
	}
	entry.lastSeen = time.Now()
	return true
}

// getVanadiumHash returns the hash of the vanadium device, if this advertisement
// is from a vanadium device.
func getVanadiumHash(a *gatt.Advertisement) ([]byte, bool) {
	md := a.ManufacturerData
	// The manufacturer data for other vanadium devices contains the hash in
	// the first 8 bytes of the data portion of the packet.  Since we can't tell
	// gatt to only call us for advertisements from a particular manufacturer, we
	// have to decode the manufacturer field to:
	//   1) figure out if this is a vanadium device
	//   2) find the hash of the data.
	// The formnat of the manufacturer data is:
	//    2-bytes for the manufacturer id (in little endian)
	//    1-byte for the length of the data segment
	//    <the actual data>
	if len(md) < 2 {
		return nil, false
	}
	if md[0] != uint8(0xe9) || md[1] != uint8(0x03) {
		return nil, false
	}
	return md[3:], true
}

// gattUUIDtoUUID converts a gatt.UUID to uuid.UUID.
func gattUUIDtoUUID(u gatt.UUID) (uuid.UUID, error) {
	// We can't just do uuid.Parse(u.String()), because the uuid code expects
	// the '-' to be in the string, but gatt.UUID.String() basically does
	// hex.EncodeToString.  Instead we have decode the bytes with the hex
	// decoder and just cast it to a uuid.UUID.
	bytes, err := hex.DecodeString(u.String())
	return uuid.UUID(bytes), err
}

func (b *bleNeighborhood) getAllServices(p gatt.Peripheral) {
	b.mu.Lock()
	h := b.pendingHashMap[p.ID()]
	delete(b.pendingHashMap, p.ID())
	b.mu.Unlock()
	defer func() {
		b.mu.Lock()
		ch := b.timeoutMap[p.ID()]
		delete(b.timeoutMap, p.ID())
		b.mu.Unlock()
		if ch != nil {
			close(ch)
		}
	}()
	/*
		if err := p.SetMTU(500); err != nil {
			log.Errorf("Failed to set MTU, err: %s", err)
			return
		}
	*/

	ss, err := p.DiscoverServices(nil)

	if err != nil {
		log.Printf("Failed to discover services, err: %s\n", err)
		return
	}

	services := map[string]*bleAdv{}
	for _, s := range ss {
		if s.UUID().Equal(attrGAPUUID) {
			continue
		}

		cs, err := p.DiscoverCharacteristics(nil, s)
		if err != nil {
			log.Printf("Failed to discover characteristics: %s\n", err)
			continue
		}

		charMap := map[string][]byte{}
		for _, c := range cs {
			if s.UUID().Equal(attrGATTUUID) {
				continue
			}
			u, err := gattUUIDtoUUID(c.UUID())
			if err != nil {
				log.Printf("malformed uuid:%v\n", c.UUID().String())
				continue
			}
			key := u.String()
			v, err := p.ReadLongCharacteristic(c)
			if err != nil {
				log.Printf("Failed to read the characteristc (%s): %v\n", key, err)
				continue

			}

			charMap[key] = v
		}
		uid, err := gattUUIDtoUUID(s.UUID())
		if err != nil {
			log.Printf("Failed to decode string: %v\n", err)
		}
		services[uid.String()] = &bleAdv{
			serviceUUID: uid,
			attrs:       charMap,
			instanceID:  charMap[strings.Replace(InstanceUUID, "-", "", -1)],
		}
	}
	b.saveDevice(h, p.ID(), services)
}

func (b *bleNeighborhood) startBLEService() error {
	d, err := gatt.NewDevice(gattOptions...)
	if err != nil {
		return err
	}
	onPeriphDiscovered := func(p gatt.Peripheral, a *gatt.Advertisement, rssi int) {
		h, v := getVanadiumHash(a)
		if v && !b.seenHash(p.ID(), h) {
			log.Println("trying to connect to ", p.Name())
			// We stop the scanning and advertising so we can connect to the new device.
			// If one device is changing too frequently we might never find all the devices,
			// since we restart the scan every time we finish connecting, but hopefully
			// that is rare.
			p.Device().StopScanning()
			p.Device().StopAdvertising()
			p.Device().Connect(p)
			b.mu.Lock()
			cancel := make(chan struct{}, 1)
			b.timeoutMap[p.ID()] = cancel
			b.mu.Unlock()
			go func() {
				select {
				case <-time.After(4 * time.Second):
				case <-cancel:
				}
				b.mu.Lock()
				if b.timeoutMap[p.ID()] == cancel {
					delete(b.timeoutMap, p.ID())
				}
				b.mu.Unlock()
				p.Device().CancelConnection(p)
				b.advertiseAndScan()
			}()
		}
	}

	onPeriphConnected := func(p gatt.Peripheral, err error) {
		if err != nil {
			log.Println("Failed to connect:", err)
			return
		}
		b.getAllServices(p)
	}

	onStateChanged := func(d gatt.Device, s gatt.State) {
		log.Printf("State: %s\n", s)
		switch s {
		case gatt.StatePoweredOn:
			defaultServices := addDefaultServices(b.name)
			for k, v := range defaultServices {
				b.services[k] = v
				d.AddService(v)
			}
			b.advertiseAndScan()
		default:
			d.StopScanning()
			d.StopAdvertising()
		}
	}

	d.Handle(
		gatt.CentralConnected(func(c gatt.Central) { log.Printf("Connect: %v\n", c.ID()) }),
		gatt.CentralDisconnected(func(c gatt.Central) { log.Printf("Disconnected: %v\n", c.ID()) }),
		gatt.PeripheralDiscovered(onPeriphDiscovered),
		gatt.PeripheralConnected(onPeriphConnected),
	)

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

func (b *bleNeighborhood) saveDevice(hash string, id string, services map[string]*bleAdv) {
	b.mu.Lock()
	defer b.mu.Unlock()
	if _, found := b.neighborsHashCache[hash]; found {
		log.Printf("Skipping a new save for the same hash (%s)\n",
			hash)
		return
	}
	oldAdvs := map[string]*bleAdv{}
	if oldEntry, ok := b.knownNeighbors[id]; ok {
		oldAdvs = oldEntry.advertisements
	}

	newEntry := &bleCacheEntry{
		id:             id,
		hash:           hash,
		advertisements: services,
		lastSeen:       time.Now(),
	}
	b.neighborsHashCache[hash] = newEntry
	b.knownNeighbors[id] = newEntry
	for id, oldAdv := range oldAdvs {
		newValue := services[id]
		if !reflect.DeepEqual(oldAdv, newValue) {
			uid := uuid.Parse(id)
			for _, s := range b.scannersByService[id] {
				s.handleChange(uid, oldAdv, newValue)
			}
		}
	}

	for id, newAdv := range newEntry.advertisements {
		if _, ok := oldAdvs[id]; !ok {
			uid := uuid.Parse(id)
			for _, s := range b.scannersByService[id] {
				s.handleChange(uid, nil, newAdv)
			}
		}
	}
}

func (b *bleNeighborhood) computeAdvertisement() *gatt.AdvPacket {
	// The hash is:
	// Hash(Hash(name),Hash(b.endpoints))
	hasher := fnv.New64()
	w := func(field string) {
		tmp := fnv.New64()
		tmp.Write([]byte(field))
		hasher.Write(tmp.Sum(nil))
	}
	w(b.name)
	for k, _ := range b.services {
		w(k)
	}
	adv := &gatt.AdvPacket{}
	adv.AppendFlags(0x06)
	adv.AppendManufacturerData(manufacturerId, hasher.Sum(nil))
	adv.AppendName(b.name)
	return adv
}
