package apis

import (
	"fmt"
	"net/http"
	"regexp"
	"strings"

	"github.com/pocketbase/pocketbase/core"
	"github.com/pocketbase/pocketbase/tools/router"
)

const installerParam = "pbinstal"

var wildcardPlaceholderRegex = regexp.MustCompile(`/{.+\.\.\.}$`)

func stripWildcard(pattern string) string {
	return wildcardPlaceholderRegex.ReplaceAllString(pattern, "")
}

// installerRedirect redirects the user to the installer dashboard UI page
// when the application needs some preliminary configurations to be done.
func installerRedirect(app core.App, cpPath string) func(*core.RequestEvent) error {
	// note: to avoid locks contention it is not concurrent safe but it
	// is expected to be updated only once during initialization
	var hasSuperuser bool

	// strip named wildcard
	cpPath = stripWildcard(cpPath)

	updateHasSuperuser := func(app core.App) error {
		total, err := app.CountRecords(core.CollectionNameSuperusers)
		if err != nil {
			return err
		}

		hasSuperuser = total > 0

		return nil
	}

	// load initial state on app init
	app.OnBootstrap().BindFunc(func(e *core.BootstrapEvent) error {
		err := e.Next()
		if err != nil {
			return err
		}

		err = updateHasSuperuser(e.App)
		if err != nil {
			return fmt.Errorf("failed to check for existing superuser: %w", err)
		}

		return nil
	})

	// update on superuser create
	app.OnRecordCreateRequest(core.CollectionNameSuperusers).BindFunc(func(e *core.RecordRequestEvent) error {
		err := e.Next()
		if err != nil {
			return err
		}

		if !hasSuperuser {
			hasSuperuser = true
		}

		return nil
	})

	return func(e *core.RequestEvent) error {
		if hasSuperuser {
			return e.Next()
		}

		isAPI := strings.HasPrefix(e.Request.URL.Path, "/api/")
		isControlPanel := strings.HasPrefix(e.Request.URL.Path, cpPath)
		wildcard := e.Request.PathValue(StaticWildcardParam)

		// skip redirect checks for API and non-root level dashboard index.html requests (css, images, etc.)
		if isAPI || (isControlPanel && wildcard != "" && wildcard != router.IndexPage) {
			return e.Next()
		}

		// check again in case the superuser was created by some other process
		if err := updateHasSuperuser(e.App); err != nil {
			return err
		}

		if hasSuperuser {
			return e.Next()
		}

		_, hasInstallerParam := e.Request.URL.Query()[installerParam]

		// redirect to the installer page
		if !hasInstallerParam {
			return e.Redirect(http.StatusTemporaryRedirect, cpPath+"?"+installerParam+"#")
		}

		return e.Next()
	}
}

// dashboardRemoveInstallerParam redirects to a non-installer
// query param in case there is already a superuser created.
//
// Note: intended to be registered only for the dashboard route
// to prevent excessive checks for every other route in installerRedirect.
func dashboardRemoveInstallerParam() func(*core.RequestEvent) error {
	return func(e *core.RequestEvent) error {
		_, hasInstallerParam := e.Request.URL.Query()[installerParam]
		if !hasInstallerParam {
			return e.Next() // nothing to remove
		}

		// clear installer param
		total, _ := e.App.CountRecords(core.CollectionNameSuperusers)
		if total > 0 {
			return e.Redirect(http.StatusTemporaryRedirect, "?")
		}

		return e.Next()
	}
}

// dashboardCacheControl adds default Cache-Control header for all
// dashboard UI resources (ignoring the root index.html path)
func dashboardCacheControl() func(*core.RequestEvent) error {
	return func(e *core.RequestEvent) error {
		if e.Request.PathValue(StaticWildcardParam) != "" {
			e.Response.Header().Set("Cache-Control", "max-age=1209600, stale-while-revalidate=86400")
		}

		return e.Next()
	}
}