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

import (
	"bytes"
	"encoding/binary"
	"encoding/hex"
	"hash/fnv"
	"log"
	"sync"
	"time"

	"mojom/v.io/x/ref/services/discovery/ble/ble"

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

func newService(uuid string, serviceId []byte, attributes map[string]string) *gatt.Service {
	s := gatt.NewService(gatt.MustParseUUID(uuid))
	for u, v := range attributes {
		s.AddCharacteristic(gatt.MustParseUUID(u)).SetValue([]byte(v))
	}
	s.AddCharacteristic(uniqueServiceId).SetValue(serviceId)
	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)
)

const (
	manufacturerId = uint16(1001)
)

var uniqueServiceId gatt.UUID

func init() {
	uniqueServiceId = gatt.MustParseUUID("f6445c7f-73fd-4b8d-98d0-c4e02b087844")

}

// 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 gattOptions = []gatt.Option{
	gatt.LnxMaxConnections(1),
	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 scanner struct {
	mu         sync.Mutex
	uuid       string
	attributes map[string]string
	ch         chan *update
	done       bool
}

func (s *scanner) handleChange(id string, oldService *ble.Service, newService *ble.Service) {
	s.mu.Lock()
	defer s.mu.Unlock()
	if s.done {
		return
	}
	matches := s.matches(id, newService)
	oldMatches := s.matches(id, oldService)
	uuid, err := hex.DecodeString(id)
	if err != nil {
		log.Fatal("Failed to decode uuid:",id,",",err)
	}
	if oldMatches {
		s.ch <- &update{
			found: false,
			adv: ble.Advertisement{
				ServiceId: uuid,
				Service: *oldService,
			},
		}
	}

	if matches {
		s.ch <- &update{
			found: true,
			adv: ble.Advertisement{
				ServiceId: uuid,
				Service: *newService,
			},
		}
	}
}

func (s *scanner) stop() {
	s.mu.Lock()
	s.done = true
	s.mu.Unlock()
}

func attributeMatch(filter map[string]string, attr map[string]string) bool {
	for k, v := range filter {
		if attr[k] != v {
			return false
		}
	}
	return true
}

func (s *scanner) matches(id string, service *ble.Service) bool {
	if service == nil {
		return false
	}
	return (s.uuid == "" || id == s.uuid) && attributeMatch(s.attributes, service.Attributes)
}

type update struct {
	found   bool
	adv ble.Advertisement
}

type bleCacheEntry struct {
	id       string
	name     string
	services map[string]*ble.Service
	hash     string
	lastSeen time.Time
}

type bleNeighborHood struct {
	mu sync.Mutex

	neighborsHashCache map[string]*bleCacheEntry
	knownNeighbors		map[string]*bleCacheEntry
	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.
	scanners 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.
	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.
	pendingHashMap map[string]string
	name           string
	device         gatt.Device
	isStopped      bool
	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),
		scanners:           make(map[int64]*scanner),
		timeoutMap:         make(map[string]chan struct{}),
		pendingHashMap:     make(map[string]string),
	}
	if err := b.startBLEService(); err != nil {
		return nil, err
	}
	return b, nil
}

func (b *bleNeighborHood) addService(id string, service ble.Service) {
	b.mu.Lock()
	b.services[id] = newService(id, service.InstanceId, service.Attributes)
	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) removeService(id string) {
	b.mu.Lock()
	delete(b.services, 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(uuid *[]byte, attr map[string]string, ch chan *update) int64 {
	s := &scanner{
		attributes: attr,
		ch:         ch,
	}
	if uuid != nil {
		s.uuid = hex.EncodeToString(*uuid)
	}
	b.mu.Lock()
	id := b.nextScanId
	b.nextScanId++
	b.scanners[id] = s
	b.mu.Unlock()
	return id
}

func (b *bleNeighborHood) removeScanner(id int64) {
	b.mu.Lock()
	scanner, found := b.scanners[id]
	if found {
		scanner.stop()
	}
	delete(b.scanners, id)
	b.mu.Unlock()
}

func (b *bleNeighborHood) Stop() error {
	b.mu.Lock()
	b.isStopped = true
	b.mu.Unlock()
	b.device.StopAdvertising()
	b.device.StopScanning()
	return nil
}

func (b *bleNeighborHood) advertiseAndScan() {
	b.mu.Lock()
	isStopped := b.isStopped
	b.mu.Unlock()
	if isStopped {
		log.Println("Quitting")
		return
	}
	log.Println("starting advertisement and scanning")
	b.device.Advertise(b.computeAdvertisement())
	b.device.Scan([]gatt.UUID{}, false)
}

// seenHash returns
func (b *bleNeighborHood) seenHash(id string, h string) bool {
	log.Println("Checking for existence of", h)
	b.mu.Lock()
	defer b.mu.Unlock()
	entry, ok := b.neighborsHashCache[h]
	if !ok {
		b.pendingHashMap[id] = h
		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()
	log.Println("Skipping connect because hashes match")
	return true
}

// shouldConnect returns true if a connection should be made to p to get an update on the
// state of the services on that device.
func (b *bleNeighborHood) shouldConnect(p gatt.Peripheral, a *gatt.Advertisement) bool {
	md := a.ManufacturerData
	// The manufuacture data for other vanadium devices have the format:
	// 0xe9 0x03 <length> <hash>
	if len(md) < 2 {
		return false
	}
	if md[0] != uint8(0xe9) || md[1] != uint8(0x03) {
		return false
	}
	hash := md[3:]
	return !b.seenHash(p.ID(), hex.EncodeToString(hash))
}

func (b *bleNeighborHood) getAllServices(p gatt.Peripheral) {
	log.Println("Connected to device")

	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 {
			log.Println("Closing channel")
			close(ch)
		}
		p.Device().CancelConnection(p)
		b.advertiseAndScan()
	}()
	/*
		if err := p.SetMTU(500); err != nil {
			log.Errorf("Failed to set MTU, err: %s", err)
			return
		}
	*/

	log.Println("Scanning for services")
	ss, err := p.DiscoverServices(nil)

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

	services := map[string]*ble.Service{}
	var name string
	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 := make(map[string]string)
		uniqueId := []byte{}
		for _, c := range cs {
			if s.UUID().Equal(attrGATTUUID) {
				if !c.UUID().Equal(attrDeviceNameUUID) {
					continue
				}
				v, err := p.ReadLongCharacteristic(c)
				if err != nil {
					log.Printf("Failed to read the name: %v\n", err)
					continue

				}
				name = string(v)
				continue
			}
			key := c.UUID().String()
			v, err := p.ReadLongCharacteristic(c)
			if err != nil {
				log.Printf("Failed to read the characteristc (%s): %v\n", key, err)
				continue

			}

			if c.UUID().Equal(uniqueServiceId) {
				uniqueId = v
				continue
			}
			charMap[key] = string(v)
		}
		services[s.UUID().String()] = &ble.Service{
			Attributes: charMap,
			InstanceId:  uniqueId,
		}
	}
	b.saveDevice(h, p.ID(), name, 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) {
		log.Printf("Found a device (%s)!\n", p.Name())
		if b.shouldConnect(p, a) {
			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):
					p.Device().CancelConnection(p)
					b.advertiseAndScan()
				case <-cancel:
				}
			}()
		}
	}

	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:
			d.AddService(newGapService(b.name))
			d.AddService(newGattService())

			b.advertiseAndScan()
		default:
			d.StopScanning()

		}
	}

	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, name string, services map[string]*ble.Service) {
	b.mu.Lock()
	defer b.mu.Unlock()
	_, found := b.neighborsHashCache[hash]
	if found {
		log.Printf("Skipping a new save for the same hash (%s) for %s\n",
			hash, name)
		return
	}
	oldServices := map[string]*ble.Service{}
	if oldEntry, ok := b.knownNeighbors[id]; ok {
		oldServices = oldEntry.services
	}

	newEntry := &bleCacheEntry{
		id: id,
		hash:     hash,
		name:     name,
		services: services,
		lastSeen: time.Now(),
	}
	b.neighborsHashCache[hash] = newEntry
	b.knownNeighbors[id] = newEntry
	log.Println("Looking through", len(b.scanners), "scanners *****")
	for _, s := range b.scanners {
		for id, oldService := range oldServices {
			newValue := services[id]
			if !reflect.DeepEqual(oldService, newValue) {
				s.handleChange(id, oldService, newValue)
			}
		}

		for id, newService := range newEntry.services {
			if _, ok := oldServices[id]; !ok {
				s.handleChange(id, nil, newService)
			}
		}
	}

}

func (b *bleNeighborHood) computeAdvertisement() *gatt.AdvPacket {
	// The hash is:
	// Hash(Hash(name),Hash(b.endpoints))
	hasher := fnv.New64()
	nameHasher := fnv.New64()
	nameHasher.Write([]byte(b.name))
	binary.Write(hasher, binary.BigEndian, nameHasher.Sum64())
	for k, _ := range b.services {
		innerHash := fnv.New64()
		innerHash.Write([]byte(k))
		binary.Write(hasher, binary.BigEndian, innerHash.Sum64())
	}
	var buf bytes.Buffer
	binary.Write(&buf, binary.BigEndian, hasher.Sum64())
	adv := &gatt.AdvPacket{}
	adv.AppendManufacturerData(manufacturerId, buf.Bytes())
	adv.AppendName(b.name)
	return adv
}
