package middleware

import (
	"context"
	"net/http"
	"strings"

	"apps/backend/internal/domain"
	"apps/backend/internal/module/ai"
	memberDomain "apps/backend/internal/module/member/domain"
	"apps/backend/internal/module/permission"
	tokenDomain "apps/backend/internal/module/token/domain"
	"apps/backend/internal/response"
)

type ctxKey int

const (
	ctxUID ctxKey = iota + 1
	ctxRoles
	ctxMember
)

func UIDFrom(ctx context.Context) (int64, bool) {
	v, ok := ctx.Value(ctxUID).(int64)
	return v, ok
}

// WithUID 讓 logic 層測試能組出「已登入」的 ctx。ctxUID 是私有型別，
// 沒有這個入口就只能繞過 UIDFrom 驗權，那測到的就不是真的授權路徑了。
func WithUID(ctx context.Context, uid int64) context.Context {
	return context.WithValue(ctx, ctxUID, uid)
}

func RolesFrom(ctx context.Context) []string {
	v, _ := ctx.Value(ctxRoles).([]string)
	return v
}

// AuthMiddleware validates Bearer access JWT.
func AuthMiddleware(issuer tokenDomain.Issuer, store memberDomain.Repository) func(http.HandlerFunc) http.HandlerFunc {
	return func(next http.HandlerFunc) http.HandlerFunc {
		return func(w http.ResponseWriter, r *http.Request) {
			h := r.Header.Get("Authorization")
			if h == "" || !strings.HasPrefix(strings.ToLower(h), "bearer ") {
				response.Fail(w, http.StatusUnauthorized, 401001, "missing authorization", nil)
				return
			}
			token := strings.TrimSpace(h[7:])
			claims, err := issuer.ParseAccess(token)
			if err != nil {
				response.Fail(w, http.StatusUnauthorized, 401002, "invalid or expired token", nil)
				return
			}
			m, err := store.FindByUID(r.Context(), claims.UID)
			if err != nil {
				response.Fail(w, http.StatusUnauthorized, 401003, "member not found", nil)
				return
			}
			if m.IsSuspended() {
				response.Fail(w, http.StatusForbidden, 403001, "account suspended", nil)
				return
			}
			ctx := context.WithValue(r.Context(), ctxUID, m.UID)
			ctx = context.WithValue(ctx, ctxRoles, m.Roles)
			ctx = context.WithValue(ctx, ctxMember, m)
			ctx = context.WithValue(ctx, domain.UIDCode, m.UID)
			// LLM 系統 prompt 語言：會員 preferred_language > Accept-Language > 繁中
			ctx = ai.WithResponseLanguage(ctx, ai.PickLanguage(m.PreferredLanguage, r.Header.Get("Accept-Language")))
			next(w, r.WithContext(ctx))
		}
	}
}

// AdminMiddleware requires permission.AdminAccess（admin 角色預設授予）.
func AdminMiddleware(next http.HandlerFunc) http.HandlerFunc {
	return RequirePermission(permission.AdminAccess)(next)
}

// RequirePermission 檢查 JWT roles 是否具備指定能力點（須在 AuthJWT 之後）.
func RequirePermission(code string) func(http.HandlerFunc) http.HandlerFunc {
	return func(next http.HandlerFunc) http.HandlerFunc {
		return func(w http.ResponseWriter, r *http.Request) {
			roles := RolesFrom(r.Context())
			if !permission.Has(roles, code) {
				response.Fail(w, http.StatusForbidden, 403002, "permission denied: "+code, nil)
				return
			}
			next(w, r)
		}
	}
}

func MemberFrom(ctx context.Context) (*memberDomain.Member, bool) {
	m, ok := ctx.Value(ctxMember).(*memberDomain.Member)
	return m, ok
}
