package web

import (
	"fmt"
	"log"
	"net/http"
	"strings"
	"time"

	"github.com/Jaculabilis/intake/core"
	"github.com/Jaculabilis/intake/web/html"
)

func (env *Env) getItem(writer http.ResponseWriter, req *http.Request) {
	source := req.PathValue("source")
	id := req.PathValue("id")

	item, err := core.GetItem(env.db, source, id)
	if err != nil {
		http.Error(writer, err.Error(), 500)
		return
	}
	html.Item(writer, html.ItemData{Item: item})
}

func (env *Env) deleteItem(writer http.ResponseWriter, req *http.Request) {
	source := req.PathValue("source")
	id := req.PathValue("id")

	_, err := core.DeactivateItem(env.db, source, id)
	if err != nil {
		http.Error(writer, err.Error(), 500)
		return
	}
	item, err := core.GetItem(env.db, source, id)
	if err != nil {
		http.Error(writer, err.Error(), 500)
		return
	}
	html.Item(writer, html.ItemData{Item: item})
}

func (env *Env) puntItem(writer http.ResponseWriter, req *http.Request) {
	source := req.PathValue("source")
	id := req.PathValue("id")

	item, err := core.GetItem(env.db, source, id)
	if err != nil {
		http.Error(writer, err.Error(), 500)
		return
	}

	now := time.Now()
	tomorrow := now.Add(time.Hour * 60)
	morning := time.Date(tomorrow.Year(), tomorrow.Month(), tomorrow.Day(), 6, 0, 0, 0, time.UTC)
	til_then := int(morning.Unix()) - item.Created
	item.Tts = til_then

	if err := core.UpdateItems(env.db, []core.Item{item}); err != nil {
		http.Error(writer, err.Error(), 500)
		return
	}

	html.Item(writer, html.ItemData{Item: item})
}

func (env *Env) doAction(writer http.ResponseWriter, req *http.Request) {
	source := req.PathValue("source")
	id := req.PathValue("id")
	action := req.PathValue("action")

	state, envs, argv, err := core.GetSourceActionInputs(env.db, source, action)
	if err != nil {
		http.Error(writer, fmt.Sprintf("error: failed to load data for %s: %v", source, err), 500)
	}

	item, err := core.GetItem(env.db, source, id)
	if err != nil {
		http.Error(writer, err.Error(), 500)
		return
	}

	if item.Action[action] == nil {
		http.Error(writer, "no such action", 500)
		return
	}

	newItem, newState, errItem, err := core.ExecuteItemAction(item, argv, envs, state, core.DefaultTimeout)
	if err != nil {
		core.AddErrorItem(env.db, errItem)
		http.Error(writer, err.Error(), 500)
		return
	}

	if err = env.db.Transact(func(tx core.DB) error {
		if _err := core.UpdateItems(tx, []core.Item{newItem}); err != nil {
			return fmt.Errorf("failed to update item: %v", _err)
		}
		if _err := core.SetState(tx, source, newState); err != nil {
			return fmt.Errorf("failed to set state for %s: %v", source, _err)
		}
		return nil
	}); err != nil {
		http.Error(writer, err.Error(), 500)
	}

	html.Item(writer, html.ItemData{Item: newItem})
}

func (env *Env) massDeactivate(writer http.ResponseWriter, req *http.Request) {
	if err := req.ParseForm(); err != nil {
		log.Printf("error parsing form data: %v", err)
		http.Error(writer, "", http.StatusBadRequest)
		return
	}
	for _, item := range req.PostForm["items"] {
		i := strings.Index(item, "/")
		if i == -1 {
			log.Printf("error: invalid source/item: %s", item)
			http.Error(writer, "", http.StatusBadRequest)
			return
		}
	}
	for _, item := range req.PostForm["items"] {
		i := strings.Index(item, "/")
		source := item[:i]
		id := item[i+1:]
		active, err := core.DeactivateItem(env.db, source, id)
		if err != nil {
			log.Printf("error: failed to deactivate %s/%s: %v", source, id, err)
		}
		if active {
			log.Printf("deactivated %s/%s", source, id)
		}
	}
	writer.Header()["HX-Refresh"] = []string{"true"}
	http.Error(writer, "ok", http.StatusNoContent)
}

func (env *Env) addItem(writer http.ResponseWriter, req *http.Request) {
	if err := req.ParseForm(); err != nil {
		log.Printf("error parsing form data: %v", err)
		http.Error(writer, "", http.StatusBadRequest)
		return
	}

	exists, err := core.SourceExists(env.db, "default")
	if err != nil {
		http.Error(writer, fmt.Sprintf("error: failed to check for source: %v", err), 500)
		return
	}
	if !exists {
		if err := core.AddSource(env.db, "default"); err != nil {
			http.Error(writer, fmt.Sprintf("error: failed to add source: %v", err), 500)
			return
		}
	}

	id := core.RandomHex(16)

	title := req.PostForm.Get("title")
	link := req.PostForm.Get("link")
	body := req.PostForm.Get("body")

	item := core.Item{
		Source: "default",
		Id:     id,
		Title:  title,
		Link:   link,
		Body:   body,
	}

	now := time.Now().Unix()
	if ttl := req.PostForm.Get("ttl"); ttl != "" {
		ttl, _ := time.Parse("2006-01-02T15:04", ttl)
		item.Ttl = int(ttl.Unix() - now)
	}
	if ttd := req.PostForm.Get("ttd"); ttd != "" {
		ttd, _ := time.Parse("2006-01-02T15:04", ttd)
		item.Ttd = int(ttd.Unix() - now)
	}
	if tts := req.PostForm.Get("tts"); tts != "" {
		tts, _ := time.Parse("2006-01-02T15:04", tts)
		item.Tts = int(tts.Unix() - now)
	}

	if err := core.AddItems(env.db, []core.Item{item}); err != nil {
		http.Error(writer, fmt.Sprintf("error: failed to add item: %s", err), 500)
		return
	}

	item, err = core.GetItem(env.db, "default", id)
	if err != nil {
		http.Error(writer, err.Error(), 500)
		return
	}

	data := html.ItemData{
		Item: item,
	}
	html.Item(writer, data)
}