package webdebug

import (
	"crypto/ed25519"
	"crypto/rand"
	"database/sql"
	"encoding/json"
	"fmt"
	"net/http"
	"strconv"
	"time"

	httputils "git.mstar.dev/mstar/goutils/http"
	"git.mstar.dev/mstar/goutils/sliceutils"
	"github.com/rs/zerolog/log"

	"git.mstar.dev/mstar/linstrom/storage-new/dbgen"
	"git.mstar.dev/mstar/linstrom/storage-new/models"
	webshared "git.mstar.dev/mstar/linstrom/web/shared"
)

func getNonDeletedUsers(w http.ResponseWriter, r *http.Request) {
	pageStr := r.FormValue("page")
	page := 0
	if pageStr != "" {
		var err error
		page, err = strconv.Atoi(pageStr)
		if err != nil {
			httputils.HttpErr(w, 0, "page is not a number", http.StatusBadRequest)
			return
		}
	}
	users, err := dbgen.User.GetPagedAllNonDeleted(uint(page))
	if err != nil {
		httputils.HttpErr(w, 0, "failed to get users", http.StatusInternalServerError)
		return
	}
	marshalled, err := json.Marshal(sliceutils.Map(users, func(t models.User) webshared.User {
		u := webshared.User{}
		u.FromModel(&t)
		return u
	}))
	if err != nil {
		httputils.HttpErr(w, 0, "failed to marshal users", http.StatusInternalServerError)
		return
	}
	fmt.Fprint(w, string(marshalled))
}

func createLocalUser(w http.ResponseWriter, r *http.Request) {
	type Inbound struct {
		Username    string     `json:"username"`
		Displayname string     `json:"displayname"`
		Description string     `json:"description"`
		Birthday    *time.Time `json:"birthday"`
		Location    *string    `json:"location"`
		IsBot       bool       `json:"is_bot"`
	}
	jsonDecoder := json.NewDecoder(r.Body)
	data := Inbound{}
	err := jsonDecoder.Decode(&data)
	if err != nil {
		httputils.HttpErr(w, 0, "decode failed", http.StatusBadRequest)
		return
	}

	publicKey, privateKey, err := ed25519.GenerateKey(nil)
	pkeyId := make([]byte, 64)
	_, err = rand.Read(pkeyId)
	if err != nil {
		log.Error().Err(err).Msg("Failed to generate passkey id")
		httputils.HttpErr(w, 0, "failed to generate passkey id", http.StatusInternalServerError)
		return
	}

	u := dbgen.User
	query := u.Select(
		u.Username,
		u.DisplayName,
		u.Description,
		u.IsBot,
		u.ServerId,
		u.PrivateKey,
		u.PublicKey,
		u.PasskeyId,
	)
	if data.Birthday != nil {
		query = query.Select(u.Birthday)
	}
	if data.Location != nil {
		query = query.Select(u.Location)
	}
	user := models.User{
		Username:    data.Username,
		DisplayName: data.Displayname,
		Description: data.Description,
		IsBot:       data.IsBot,
		ServerId:    1, // Hardcoded, Self is always first ID
		PublicKey:   publicKey,
		PrivateKey:  privateKey,
		PasskeyId:   pkeyId,
	}
	if data.Birthday != nil {
		user.Birthday = sql.NullTime{Valid: true, Time: *data.Birthday}
	}
	if data.Location != nil {
		user.Location = sql.NullString{Valid: true, String: *data.Location}
	}
	if err = u.Create(&user); err != nil {
		log.Error().Err(err).Msg("failed to create new local user")
		httputils.HttpErr(w, 0, "db failure", http.StatusInternalServerError)
	}
}

func deleteUser(w http.ResponseWriter, r *http.Request) {
	id := r.FormValue("id")
	dbgen.User.Where(dbgen.User.ID.Eq(id)).Delete()
	w.WriteHeader(http.StatusOK)
}
