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

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
}
