package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
	scribble "github.com/nanobox-io/golang-scribble"
)

type Surfer struct {
	Name     string `json:"name"`
	Color    string `json:"color"`
	Priority string `json:"priority"`
	Score    string `json:"score"`
}

type Heat struct {
	Name     string   `json:"name"`
	Category string   `json:"category"`
	Number   int      `json:"number"`
	Timer    int      `json:"timer"`
	Status   string   `json:"status"`
	Surfers  []Surfer `json:"surfers"`
}

func heatName(heat Heat) string {
	return fmt.Sprintf("%s.%d.%s", heat.Name, heat.Number, heat.Category)
}

func (w *Webapp) SaveHeat(c *gin.Context) {
	var heat Heat

	err := c.ShouldBind(&heat)

	if err != nil {
		log.Printf("req error: %+v", err)
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	log.Printf("heat: %+v", heat)

	heat.Status = "idle"

	err = w.DB.Write("Heat", heatName(heat), heat)
	if err != nil {
		log.Printf("set error: %+v", err)
		c.JSON(http.StatusInternalServerError, gin.H{"status": fmt.Sprintf("Error: %+v", err)})
		return
	}

	c.JSON(http.StatusOK, gin.H{"status": "saved"})
}

func (w *Webapp) DeleteHeat(c *gin.Context) {
	var heat Heat

	err := c.ShouldBind(&heat)

	if err != nil {
		log.Printf("req error: %+v", err)
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	log.Printf("heat: %+v", heat)

	err = w.DB.Delete("Heat", heatName(heat))
	if err != nil {
		log.Printf("set error: %+v", err)
		c.JSON(http.StatusInternalServerError, gin.H{"status": fmt.Sprintf("Error: %+v", err)})
		return
	}

	c.JSON(http.StatusOK, gin.H{"status": "deleted"})
}

func (w *Webapp) LoadRunning(c *gin.Context) {
	heats := loadHeats(w.DB)

	for _, heat := range heats {
		if heat.Status == "running" {
			c.JSON(http.StatusOK, heat)
			return
		}
	}

	c.JSON(http.StatusNoContent, "")
}

func (w *Webapp) LoadHeats(c *gin.Context) {
	heats := loadHeats(w.DB)

	c.JSON(http.StatusOK, heats)

	log.Printf("heats: %+v", heats)
}

func (w *Webapp) StartHeatTimer(c *gin.Context) {
	var msg Message
	var err error
	var timer time.Duration

	if w.Stream.Start {
		c.JSON(http.StatusOK, w.Stream.Duration)
		return
	}

	err = c.ShouldBind(&msg)
	if err != nil {
		log.Printf("req error: %+v", err)
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	timer, err = time.ParseDuration(msg.Duration)
	if err != nil {
		log.Printf("req error: %+v", err)
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	w.Stream.Duration = timer
	w.Stream.Start = true

	startHeat(w.DB, *w.Stream.Heat)

	log.Printf("start timer %s - received %s", w.Stream.Duration, msg.Duration)
	c.JSON(http.StatusOK, w.Stream.Duration)
}

func (w *Webapp) StopHeatTimer(c *gin.Context) {
	if !w.Stream.Start {
		c.JSON(http.StatusOK, w.Stream.Duration)
		return
	}

	stopHeat(w.DB, *w.Stream.Heat)
	w.Stream.Start = false
	w.Stream.Duration = 0

	log.Printf("start timer %s", w.Stream.Duration)
	c.JSON(http.StatusOK, w.Stream.Duration)
}

func loadHeats(db *scribble.Driver) []Heat {
	records, err := db.ReadAll("Heat")
	if err != nil {
		fmt.Printf("read error: %+v", err)
	}

	heats := make([]Heat, 0)
	for _, record := range records {
		var heat Heat
		err = json.Unmarshal([]byte(record), &heat)
		if err != nil {
			fmt.Printf("decode error: %+v", err)
		}
		heats = append(heats, heat)
	}

	return heats
}

func startHeat(db *scribble.Driver, heat Heat) error {
	log.Printf("heat: %+v", heat)

	heat.Status = "running"

	err := db.Write("Heat", heatName(heat), heat)
	if err != nil {
		log.Printf("set error: %+v", err)
		return err
	}

	return nil
}

func stopHeat(db *scribble.Driver, heat Heat) error {

	log.Printf("heat: %+v", heat)

	heat.Status = "ended"

	err := db.Write("Heat", heatName(heat), heat)
	if err != nil {
		log.Printf("set error: %+v", err)
		return err
	}

	return nil
}
