// Package users handles user-related custom functionality.
package users

import (
	"log"
	"net/http"

	"github.com/henrygd/beszel/internal/migrations"

	"github.com/pocketbase/dbx"
	"github.com/pocketbase/pocketbase/core"
)

type UserManager struct {
	app core.App
}

func NewUserManager(app core.App) *UserManager {
	return &UserManager{
		app: app,
	}
}

// Initialize user role if not set
func (um *UserManager) InitializeUserRole(e *core.RecordEvent) error {
	if e.Record.GetString("role") == "" {
		e.Record.Set("role", "user")
	}
	return e.Next()
}

// Initialize user settings with defaults if not set
func (um *UserManager) InitializeUserSettings(e *core.RecordEvent) error {
	record := e.Record
	// intialize settings with defaults (zero values can be ignored)
	settings := struct {
		ChartTime string   `json:"chartTime"`
		Emails    []string `json:"emails"`
	}{
		ChartTime: "1h",
	}
	record.UnmarshalJSONField("settings", &settings)
	// get user email from auth record
	var user struct {
		Email string `db:"email"`
	}
	err := e.App.DB().NewQuery("SELECT email FROM users WHERE id = {:id}").Bind(dbx.Params{
		"id": record.GetString("user"),
	}).One(&user)
	if err != nil {
		log.Println("failed to get user email", "err", err)
		return err
	}
	settings.Emails = []string{user.Email}
	record.Set("settings", settings)
	return e.Next()
}

// Custom API endpoint to create the first user.
// Mimics previous default behavior in PocketBase < 0.23.0 allowing user to be created through the Beszel UI.
func (um *UserManager) CreateFirstUser(e *core.RequestEvent) error {
	// check that there are no users
	totalUsers, err := um.app.CountRecords("users")
	if err != nil || totalUsers > 0 {
		return e.JSON(http.StatusForbidden, map[string]string{"err": "Forbidden"})
	}
	// check that there is only one superuser and the email matches the email of the superuser we set up in initial-settings.go
	adminUsers, err := um.app.FindAllRecords(core.CollectionNameSuperusers)
	if err != nil || len(adminUsers) != 1 || adminUsers[0].GetString("email") != migrations.TempAdminEmail {
		return e.JSON(http.StatusForbidden, map[string]string{"err": "Forbidden"})
	}
	// create first user using supplied email and password in request body
	data := struct {
		Email    string `json:"email"`
		Password string `json:"password"`
	}{}
	if err := e.BindBody(&data); err != nil {
		return e.JSON(http.StatusBadRequest, map[string]string{"err": err.Error()})
	}
	if data.Email == "" || data.Password == "" {
		return e.JSON(http.StatusBadRequest, map[string]string{"err": "Bad request"})
	}

	collection, _ := um.app.FindCollectionByNameOrId("users")
	user := core.NewRecord(collection)
	user.SetEmail(data.Email)
	user.SetPassword(data.Password)
	user.Set("role", "admin")
	user.Set("verified", true)
	if err := um.app.Save(user); err != nil {
		return e.JSON(http.StatusInternalServerError, map[string]string{"err": err.Error()})
	}
	// create superuser using the email of the first user
	collection, _ = um.app.FindCollectionByNameOrId(core.CollectionNameSuperusers)
	adminUser := core.NewRecord(collection)
	adminUser.SetEmail(data.Email)
	adminUser.SetPassword(data.Password)
	if err := um.app.Save(adminUser); err != nil {
		return e.JSON(http.StatusInternalServerError, map[string]string{"err": err.Error()})
	}
	// delete the intial superuser
	if err := um.app.Delete(adminUsers[0]); err != nil {
		return e.JSON(http.StatusInternalServerError, map[string]string{"err": err.Error()})
	}
	return e.JSON(http.StatusOK, map[string]string{"msg": "User created"})
}
