package main

import (
	"crypto/rand"
	"encoding/hex"
	"log/slog"
	"net/http"
	"strconv"
	"sync"

	"brainminder.speedtech.it/internal/database"
	"brainminder.speedtech.it/internal/funcs"
	"brainminder.speedtech.it/internal/smtp"
	"brainminder.speedtech.it/models"
	"github.com/gorilla/sessions"
)

type application struct {
	config       config
	db           *database.DB
	logger       *slog.Logger
	mailer       *smtp.Mailer
	sessionStore *sessions.CookieStore
	wg           sync.WaitGroup
}

func (app *application) getCurrentNotebookId(r *http.Request) int64 {
	session, _ := app.sessionStore.Get(r, "session")
	currentNotebookId := session.Values["current_notebook_id"]
	var notebookId int64 = -1
	if currentNotebookId != nil {
		notebookId, _ = strconv.ParseInt(currentNotebookId.(string), 10, 64)
	}
	return notebookId
}

func (app *application) saveSessionValue(w http.ResponseWriter, r *http.Request, name string, value any) {
	session, err := app.sessionStore.Get(r, "sessions")
	if err != nil {
		app.serverError(w, r, err)
		return
	}

	session.Values[name] = value

	err = session.Save(r, w)
	if err != nil {
		app.serverError(w, r, err)
		return
	}
}

func (app *application) getSessionValue(w http.ResponseWriter, r *http.Request, name string) any {
	session, err := app.sessionStore.Get(r, "sessions")
	if err != nil {
		app.serverError(w, r, err)
		return nil
	}

	if value, isMapContainsKey := session.Values[name]; isMapContainsKey {
		return value
	}
	return nil
}

func (app *application) removeSessionValue(w http.ResponseWriter, r *http.Request, name string) {
	session, err := app.sessionStore.Get(r, "sessions")
	if err != nil {
		app.serverError(w, r, err)
		return
	}

	delete(session.Values, name)

	err = session.Save(r, w)
	if err != nil {
		app.serverError(w, r, err)
	}
}

func (app *application) getCategoriesAsOptions() []funcs.WidgetOption {
	categoryModel := &models.CategoryModel{DB: app.db}
	return categoryModel.AllAsOptions()
}

func (app *application) getCategoriesAsMap() map[string]string {
	categoryModel := &models.CategoryModel{DB: app.db}
	return categoryModel.AllAsMap()
}

func (app *application) getTypesAsOptions(r *http.Request) []funcs.WidgetOption {
	typeModel := &models.TypeModel{DB: app.db}
	criteria := map[string]any{
		"notebook_id": app.getCurrentNotebookId(r),
	}
	return typeModel.FindAsOptions(criteria)
}

func (app *application) getNotebooksAsOptions() []funcs.WidgetOption {
	notebookModel := &models.NotebookModel{DB: app.db}
	return notebookModel.AllAsOptions(false)
}

func (app *application) generateSecureToken(length int) string {
	b := make([]byte, length)
	if _, err := rand.Read(b); err != nil {
		return ""
	}
	return hex.EncodeToString(b)
}
