package meta

import (
	"context"

	"nadir/internal/auth"
	"nadir/internal/module"
	"nadir/internal/rbac"

	"github.com/danielgtaylor/huma/v2"
)

// WhoamiInput carries the session cookie. The endpoint is not behind the RBAC
// middleware (it requires no specific permission), so it validates the session
// itself.
type WhoamiInput struct {
	SessionID string `cookie:"nadir_session_id"`
	Auth      string `header:"Authorization"`
}

// WhoamiBody reports who the caller is and, per module, which permissions they
// actually hold. Combined with /api/_modules (the full module/permission grid),
// this gives the frontend everything it needs to render the permission matrix.
type WhoamiBody struct {
	Username    string              `json:"username" example:"urania" doc:"Authenticated username"`
	Permissions map[string][]string `json:"permissions" doc:"Module ID -> permissions the caller holds. Modules where they hold none are omitted."`
}

type WhoamiOutput struct{ Body WhoamiBody }

// RegisterWhoami adds the current-user endpoint. It resolves the caller's
// concrete grants by asking the RBAC store about each module's permissions,
// so "*" wildcards in roles are expanded for free.
func RegisterWhoami(api huma.API, sessions *auth.SessionStore, tokens *auth.TokenAuth, roles *rbac.RBAC, mods []module.Module) {
	huma.Register(api, huma.Operation{
		OperationID: "whoami",
		Method:      "GET",
		Path:        "/api/whoami",
		Summary:     "Get the current user and their permissions",
		Description: "Returns the authenticated username and, per module, the " +
			"permissions the caller holds (wildcards resolved). Pair with " +
			"/api/_modules to render the full permission matrix.",
		Tags:   []string{"Meta"},
		Errors: []int{401, 429},
	}, func(ctx context.Context, in *WhoamiInput) (*WhoamiOutput, error) {
		var username string

		if raw, isBearer := auth.BearerToken(in.Auth); isBearer {
			if tokens == nil {
				return nil, huma.Error401Unauthorized("unauthorized")
			}
			name, ok, throttled := tokens.Verify(auth.ClientIP(ctx), raw)
			if throttled {
				return nil, huma.Error429TooManyRequests("too many failed token attempts; wait a minute")
			}
			if !ok {
				return nil, huma.Error401Unauthorized("unauthorized")
			}
			username = name
		} else {
			sess, ok := sessions.GetByToken(in.SessionID)
			if !ok {
				return nil, huma.Error401Unauthorized("unauthorized")
			}
			username = sess.Username
		}

		held := make(map[string][]string)
		for _, m := range mods {
			var perms []string
			for _, p := range m.Permissions() {
				if roles.Can(username, m.ID(), p) {
					perms = append(perms, string(p))
				}
			}
			if len(perms) > 0 {
				held[m.ID()] = perms
			}
		}

		out := &WhoamiOutput{}
		out.Body = WhoamiBody{Username: username, Permissions: held}
		return out, nil
	})
}

