package router

import (
	"etrismartfarmpoc/watcher"
	"fmt"
	"log"
	"net/http"
	"sync"

	"github.com/gorilla/mux"
	"github.com/gorilla/websocket"
)

var upgrader = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
	CheckOrigin:     func(r *http.Request) bool { return true },
}

var notifications []chan *Notification
var notiMutex sync.Mutex

func sendNotification(noti *Notification) {
	// notiMutex.Lock()
	// defer notiMutex.Unlock()
	for _, ch := range notifications {
		ch <- noti
	}
}

func removeNotification(noti chan *Notification) {
	notiMutex.Lock()
	defer notiMutex.Unlock()
	for i, e := range notifications {
		if e == noti {
			notifications[i] = notifications[len(notifications)-1]
			notifications = notifications[:len(notifications)-1]
		}
	}
}

func GetNotification(w http.ResponseWriter, r *http.Request) {
	notiChan := make(chan *Notification, 1)
	notiMutex.Lock()
	notifications = append(notifications, notiChan)
	notiMutex.Unlock()
	conn, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		w.Write([]byte(err.Error()))
		return
	}

	for {
		notification := <-notiChan
		// fmt.Println("Write!!", discoveredDevices)
		if conn.WriteJSON(notification) != nil {
			log.Println(err)
			w.WriteHeader(http.StatusBadRequest)
			removeNotification(notiChan)
			notiChan = nil
			return
		}
	}
}

var watchers = map[string]*watcher.DeviceWatcher{}

func GetDeviceWatch(w http.ResponseWriter, r *http.Request) {

	vars := mux.Vars(r)
	did, ok := vars["id"]
	if !ok {
		w.WriteHeader(http.StatusBadRequest)
		w.Write([]byte("not found did"))
		return
	}

	conn, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		w.Write([]byte(err.Error()))
		return
	}

	if !checkDid(did) {
		w.WriteHeader(http.StatusBadRequest)
		w.Write([]byte("not exist did"))
		return
	}

	s := make(chan map[string]interface{})
	defer close(s)
	ec := make(chan error)
	defer close(ec)

	watch, ok := watchers[did]

	if !ok {
		watch = &watcher.DeviceWatcher{}
		watchers[did] = watch
	}

	watch.Subscribe(s)

	defer func() {
		cnt := watch.Desubscribe(s)
		if cnt == 0 {
			delete(watchers, did)
			log.Println("delete watchers: ", watchers)
		}
	}()

	go func() {
		_, _, err := conn.ReadMessage()
		if err != nil {
			ec <- err
		}
	}()
	for {
		select {
		case param := <-s:
			if conn.WriteJSON(param) != nil {
				log.Println(err)
				w.WriteHeader(http.StatusBadRequest)
				return
			}

		case <-r.Context().Done():
			fmt.Println("see you later~")
			w.WriteHeader(http.StatusOK)
			w.Write([]byte("See you later~"))
			return
		case <-ec:
			return
		}

	}
}

func checkDid(did string) bool {
	return true
}
