package main

import (
	"bufio"
	"encoding/json"
	"flag"
	"github.com/rs/zerolog/log"
	"net/http"
	"os"
	"strconv"
	"strings"
	"time"
)

type Event struct {
	Name           string
	EventTimestamp time.Time
}

var eventlog string

//Current State
var lastEvent Event
var currentState map[string]map[string]int64 //Per Name per Day in Secounds


func main() {
	eventlogPath := flag.String("eventlog", "/var/ett/eventlog", "Where to store the eventlog file")

	flag.Parse()
	eventlog = *eventlogPath

	log.Info().Msg("Start Time Tracking Service")
	currentState =  make(map[string]map[string]int64)

	defer func() {
		e := Event{
			Name:           "Nothing",
			EventTimestamp: time.Now(),
		}
		addEvent(e)
	}()

	readStateFromFile()

	runHttpServer()
}

func runHttpServer() {
	http.HandleFunc("/", func (w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("<h1>Time Tracking</h1>"))
		w.Write([]byte("<h3>Today</h3>"))
		for tag, _ := range currentState {
			i := currentState[tag][time.Now().Format("02.01.06")]
			s := strconv.FormatInt(i, 10)
			line := tag+": "+s+"<br>"
			w.Write([]byte(line))
		}
		w.Write([]byte("<h3>Last 7 Days</h3>"))
		for tag, _ := range currentState {
			var gi int64
			for i := 0; i <= 7; i++ {
				g := -1 * 24 * i
				t := time.Now().Add(time.Duration(g) * time.Hour)
				secounds := currentState[tag][t.Format("02.01.06")]
				gi = gi + secounds
			}

			s := strconv.FormatInt(gi, 10)
			line := tag+": "+s+"<br>"
			w.Write([]byte(line))
		}
	})
	http.HandleFunc("/current", func(w http.ResponseWriter, r *http.Request) {
		res, err := json.Marshal(currentState)
		if err != nil {
			log.Fatal().Err(err).Msg("Cant Marshal Current State")
		}
		w.Write(res)
	})


	http.HandleFunc("/tags", func(w http.ResponseWriter, r *http.Request) {
		var tags []string
		for s, _ := range currentState {
			tags = append(tags, s)
		}
		res, err := json.Marshal(tags)
		if err != nil {
			log.Fatal().Err(err).Msg("Cant Marshal Tag list")
		}
		w.Write(res)
	})

	http.HandleFunc("/state", func(w http.ResponseWriter, r *http.Request) {
		res, err := json.Marshal(currentState)
		if err != nil {
			log.Fatal().Err(err).Msg("Cant Marshal Tag list")
		}
		w.Write(res)
	})

	http.HandleFunc("/event", func(w http.ResponseWriter, r *http.Request) {
		err := r.ParseForm()
		if err != nil {
			log.Warn().Err(err).Msg("Cant pars form Data from Request to add event")
			w.WriteHeader(http.StatusBadRequest)
			w.Write([]byte("Cant parse form Data"))
			return
		}
		d := r.FormValue("time")
		eventTimestamp := time.Now()
		if d != "" {
			eventTimestamp, err = time.Parse(time.RFC3339 , d)
			if err != nil {
				log.Warn().Err(err).Str("TimeString", d).Msg("Cant parse time from http get parameter")
			}
			w.WriteHeader(http.StatusBadRequest)
			w.Write([]byte("Cant parse date from get paremter, please use RFC3339 Data"))
			return
		}


		name := r.FormValue("name")

		e := Event{
			Name:           name,
			EventTimestamp: eventTimestamp,
		}

		addEvent(e)
	})

	http.ListenAndServe(":8080", nil)
}

func readStateFromFile() {
	if _, err := os.Stat(eventlog); err == nil {
		// path/to/whatever exists
		file, err := os.Open(eventlog)

		if err != nil {
			log.Fatal().Err(err).Msg("Cant open file")
		}
		defer file.Close()

		scanner := bufio.NewScanner(file)
		scanner.Split(bufio.ScanLines)

		for scanner.Scan() {
			details := strings.Split(scanner.Text(), ";")
			t, err := time.Parse(time.RFC3339 , details[0])
			if err != nil {
				log.Fatal().Err(err).Str("TimeString", details[0]).Msg("Cant parse time from eventlog")
			}
			e := Event{
				Name:           details[1],
				EventTimestamp: t,
			}

			handleEvent(e)
		}
	}
}

func saveEvent(e Event) {
	var line string
	line = e.EventTimestamp.Format(time.RFC3339)+";"+e.Name +"\r\n"
	f, err := os.OpenFile(eventlog, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
	if err != nil {
		panic(err)
	}

	defer f.Close()

	if _, err = f.WriteString(line); err != nil {
		panic(err)
	}

}

func addEvent(e Event)  {
	//Write Event to Log
	saveEvent(e)
	handleEvent(e)
}

func handleEvent(e Event)  {
	log.Debug().Msg("Handle New Event")
	if lastEvent.Name != "" {
		duration := e.EventTimestamp.Sub(lastEvent.EventTimestamp)
		log.Debug().Int64("Duration", int64(duration.Seconds())).Str("LastEventName", lastEvent.Name).Msg("Calculatet Duration for last event")
		//Add to state
		currentDuration := currentState[lastEvent.Name][lastEvent.EventTimestamp.Format("02.01.06")]
		if len(currentState[lastEvent.Name]) == 0 {
			currentState[lastEvent.Name] = make(map[string]int64)
		}
		currentDuration += int64(duration.Seconds())
		log.Debug().Int64("Day Duration", currentDuration).Str("Day", lastEvent.EventTimestamp.Format("02.01.06")).Str("typ", lastEvent.Name).Msg("Add Duration to Day")
		currentState[lastEvent.Name][lastEvent.EventTimestamp.Format("02.01.06")] = currentDuration
	}

	lastEvent = e
}