package common

import (
	"fmt"
	"context"
	"net/http"

	apns "github.com/sideshow/apns2"
	"party.at/party/cmd/party/parlament"
	"party.at/party/internal/data"
	"party.at/party/internal/jsonlog"
	"party.at/party/internal/mailer"
)

type Config struct {
	Port int
	Env  string

	DB struct {
		DSN          string
		MaxOpenConns int
		MaxIdleConns int
		MaxIdleTime  string
	}

	Limiter struct {
		RPS     float64
		Burst   int
		Enabled bool
	}

	SMTP struct {
		Host     string
		Port     int
		Username string
		Password string
		Sender   string
	}

	CORS struct {
		TrustedOrigins []string
	}

	APNS struct {
		KeyPath  string
		KeyID    string
		TeamID   string
		BundleID string
	}
}

type Application struct {
	Config   Config
	Logger   *jsonlog.Logger
	Models   data.Models
	Mailer   mailer.Mailer
	Parlament *parlament.Client
	APNS     *apns.Client
	Env      string

	LimiterEnabled     bool
	LimiterRPS         float64
	LimiterBurst       int
	CORSTrustedOrigins []string
}

func (app *Application) background(fn func()) {
	go func() {
		defer func() {
			if err := recover(); err != nil {
				app.Logger.PrintError(fmt.Errorf("%s", err), nil)
			}
		}()
		fn()
	}()
}

type contextKey string

const userKey contextKey = "web_user"
const permissionsKey contextKey = "web_permissions"

func SetUser(r *http.Request, user *data.User) *http.Request {
	return r.WithContext(context.WithValue(r.Context(), userKey, user))
}

func GetUser(r *http.Request) *data.User {
	user, ok := r.Context().Value(userKey).(*data.User)
	if !ok {
		return data.AnonymousUser
	}
	return user
}

func SetPermissions(r *http.Request, permissions data.Permissions) *http.Request {
	return r.WithContext(context.WithValue(r.Context(), permissionsKey, permissions))
}

func GetPermissions(r *http.Request) data.Permissions {
	permissions, ok := r.Context().Value(permissionsKey).(data.Permissions)
	if !ok {
		return data.Permissions{}
	}
	return permissions
}
