package server

import (
	"net/http"
	"time"

	httputil "git.mstar.dev/mstar/goutils/http"
	"github.com/google/jsonapi"
	"github.com/rs/zerolog/hlog"

	"git.mstar.dev/mstar/linstrom/shared"
	"git.mstar.dev/mstar/linstrom/storage"
)

// Notes
func linstromGetNote(w http.ResponseWriter, r *http.Request) {
	store := StorageFromRequest(r)
	noteId := NoteIdFromRequest(r)
	log := hlog.FromRequest(r)
	sNote, err := store.FindNoteById(noteId)
	switch err {
	case nil:
		// Found, progress past switch statement
	case storage.ErrEntryNotFound:
		httputil.HttpErr(w, HttpErrIdNotFound, "Note not found", http.StatusNotFound)
		return
	default:
		log.Error().Err(err).Str("note-id", noteId).Msg("Failed to get note from db")
		httputil.HttpErr(
			w,
			HttpErrIdDbFailure,
			"Failed to get note from db",
			http.StatusInternalServerError,
		)
		return
	}
	note, err := convertNoteStorageToLinstrom(sNote, store)
	if err != nil {
		log.Error().
			Err(err).
			Str("note-id", noteId).
			Msg("Failed to convert note into linstrom api form")
		httputil.HttpErr(
			w,
			HttpErrIdConversionFailure,
			"Failed to convert note",
			http.StatusInternalServerError,
		)
		return
	}
	err = jsonapi.MarshalPayload(w, note)
	if err != nil {
		log.Error().Err(err).Any("note", note).Msg("Failed to marshal and send note")
		httputil.HttpErr(
			w,
			HttpErrIdJsonMarshalFail,
			"Failed to convert note",
			http.StatusInternalServerError,
		)
	}
}

func linstromUpdateNote(w http.ResponseWriter, r *http.Request) {}
func linstromNewNote(w http.ResponseWriter, r *http.Request) {
	store := StorageFromRequest(r)
	actorId, ok := ActorIdFromRequest(r)
	log := hlog.FromRequest(r)

	if !ok {
		httputil.HttpErr(
			w,
			HttpErrIdNotAuthenticated,
			"Needs a valid session to create new notes",
			http.StatusUnauthorized,
		)
		return
	}

	newNote := linstromNote{}
	err := jsonapi.UnmarshalPayload(r.Body, &newNote)
	if err != nil {
		log.Warn().Err(err).Msg("Failed to unmarshal body")
		httputil.HttpErr(w, HttpErrIdBadRequest, "bad body", http.StatusBadRequest)
		return
	}

	if newNote.AuthorId != actorId {
		log.Debug().
			Str("actor-id", actorId).
			Str("target-id", newNote.AuthorId).
			Msg("Blocking attempt at creating a note for a different account")
		httputil.HttpErr(
			w,
			HttpErrIdNotAllowed,
			"creating a note for someone else is not allowed",
			http.StatusForbidden,
		)
		return
	}

	rawTags := shared.TagsFromText(newNote.RawContent)

	note, err := store.CreateNoteLocal(
		actorId,
		newNote.RawContent,
		newNote.ContentWarning,
		time.Now(),
		newNote.AttachmentIds,
		newNote.EmoteIds,
		newNote.InReplyToId,
		newNote.QuotesId,
		storage.NoteAccessLevel(newNote.AccessLevel),
		rawTags,
		// tags []string
	)
	if err != nil {
		log.Error().Err(err).Any("note", newNote).Msg("Failed to insert new note into storage")
		httputil.HttpErr(
			w,
			HttpErrIdDbFailure,
			"Failed to insert new note into db",
			http.StatusInternalServerError,
		)
		return
	}
	_ = note
}
func linstromDeleteNote(w http.ResponseWriter, r *http.Request) {}

// Reactions
func linstromGetReactions(w http.ResponseWriter, r *http.Request)   {}
func linstromAddReaction(w http.ResponseWriter, r *http.Request)    {}
func linstromDeleteReaction(w http.ResponseWriter, r *http.Request) {}
func linstromUpdateReaction(w http.ResponseWriter, r *http.Request) {}

// Boosts
func linstromGetBoosts(w http.ResponseWriter, r *http.Request)   {}
func linstromAddBoost(w http.ResponseWriter, r *http.Request)    {}
func linstromRemoveBoost(w http.ResponseWriter, r *http.Request) {}

// Quotes
func linstromGetQuotes(w http.ResponseWriter, r *http.Request) {}
func linstromAddQuote(w http.ResponseWriter, r *http.Request)  {}

// No delete quote since quotes are their own notes with an extra attribute

// Pinning
func linstromPinNote(w http.ResponseWriter, r *http.Request)   {}
func linstromUnpinNote(w http.ResponseWriter, r *http.Request) {}

// Reporting
func linstromReportNote(w http.ResponseWriter, r *http.Request)        {}
func linstromRetractReportNote(w http.ResponseWriter, r *http.Request) {}

// Admin tools
// TODO: Figure out more admin tools for managing notes
// Delete can be done via normal note delete, common permission check
func linstromForceCWNote(w http.ResponseWriter, r *http.Request) {}
