package app

import (
	"fmt"
	"log/slog"
	"net/http"
	"strings"

	"github.com/bitechdev/ResolveSpec/pkg/resolvespec"
	"github.com/uptrace/bunrouter"

	"git.warky.dev/wdevs/amcs/internal/generatedmodels"
	"git.warky.dev/wdevs/amcs/internal/store"
)

func registerResolveSpecAdminRoutes(mux *http.ServeMux, db *store.DB, middleware func(http.Handler) http.Handler, logger *slog.Logger) error {
	rs := resolvespec.NewHandlerWithBun(db.Bun())
	registerResolveSpecGuards(rs)
	for _, model := range resolveSpecModels() {
		if err := rs.RegisterModel(model.schema, model.entity, model.model); err != nil {
			return fmt.Errorf("register resolvespec model %s.%s: %w", model.schema, model.entity, err)
		}
	}

	rsRouter := bunrouter.New()
	resolvespec.SetupBunRouterRoutes(rsRouter, rs, nil)

	rsMount := http.StripPrefix("/api/rs", rsRouter)
	protectedRSMount := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path != "/" && strings.HasSuffix(r.URL.Path, "/") {
			trimmed := strings.TrimRight(r.URL.Path, "/")
			if trimmed == "" {
				trimmed = "/"
			}
			clone := r.Clone(r.Context())
			clone.URL.Path = trimmed
			if clone.URL.RawPath != "" {
				clone.URL.RawPath = strings.TrimRight(clone.URL.RawPath, "/")
				if clone.URL.RawPath == "" {
					clone.URL.RawPath = "/"
				}
			}
			r = clone
		}
		if r.Method == http.MethodOptions {
			rsMount.ServeHTTP(w, r)
			return
		}
		middleware(rsMount).ServeHTTP(w, r)
	})

	mux.Handle("/api/rs/", protectedRSMount)
	mux.Handle("/api/rs", http.RedirectHandler("/api/rs/openapi", http.StatusTemporaryRedirect))

	if logger != nil {
		logger.Info("resolvespec admin api enabled",
			slog.String("prefix", "/api/rs"),
			slog.Int("models", len(resolveSpecModels())),
		)
	}

	return nil
}

func registerResolveSpecGuards(rs *resolvespec.Handler) {
	mutableByEntity := map[string]map[string]struct{}{
		"projects": {
			"create": {},
			"update": {},
			"delete": {},
		},
		"thoughts": {
			"create": {},
			"update": {},
			"delete": {},
		},
		"plans": {
			"create": {},
			"update": {},
			"delete": {},
		},
		"learnings": {
			"create": {},
			"update": {},
			"delete": {},
		},
		"agent_skills": {
			"create": {},
			"update": {},
			"delete": {},
		},
		"agent_guardrails": {
			"create": {},
			"update": {},
			"delete": {},
		},
		"stored_files": {
			"update": {},
			"delete": {},
		},
	}

	rs.Hooks().Register(resolvespec.BeforeHandle, func(hookCtx *resolvespec.HookContext) error {
		switch hookCtx.Operation {
		case "read", "meta":
			return nil
		case "create", "update", "delete":
			allowedOps, ok := mutableByEntity[hookCtx.Entity]
			if !ok {
				hookCtx.Abort = true
				hookCtx.AbortCode = http.StatusForbidden
				hookCtx.AbortMessage = fmt.Sprintf("operation %q is not allowed for %s.%s", hookCtx.Operation, hookCtx.Schema, hookCtx.Entity)
				return fmt.Errorf("forbidden operation")
			}
			if _, ok := allowedOps[hookCtx.Operation]; !ok {
				hookCtx.Abort = true
				hookCtx.AbortCode = http.StatusForbidden
				hookCtx.AbortMessage = fmt.Sprintf("operation %q is not allowed for %s.%s", hookCtx.Operation, hookCtx.Schema, hookCtx.Entity)
				return fmt.Errorf("forbidden operation")
			}
			return nil
		default:
			hookCtx.Abort = true
			hookCtx.AbortCode = http.StatusBadRequest
			hookCtx.AbortMessage = fmt.Sprintf("unsupported operation %q", hookCtx.Operation)
			return fmt.Errorf("unsupported operation")
		}
	})
}

type resolveSpecModel struct {
	schema string
	entity string
	model  any
}

func resolveSpecModels() []resolveSpecModel {
	//This must be generated with relspec to include all models
	//Use the relspec command with template generation. It supprot templ.
	return []resolveSpecModel{
		// {schema: "public", entity: "activities", model: generatedmodels.ModelPublicActivities{}},
		{schema: "public", entity: "agent_guardrails", model: generatedmodels.ModelPublicAgentGuardrails{}},
		{schema: "public", entity: "agent_skills", model: generatedmodels.ModelPublicAgentSkills{}},
		{schema: "public", entity: "chat_histories", model: generatedmodels.ModelPublicChatHistories{}},
		// {schema: "public", entity: "contact_interactions", model: generatedmodels.ModelPublicContactInteractions{}},
		{schema: "public", entity: "embeddings", model: generatedmodels.ModelPublicEmbeddings{}},
		// {schema: "public", entity: "family_members", model: generatedmodels.ModelPublicFamilyMembers{}},
		// {schema: "public", entity: "household_items", model: generatedmodels.ModelPublicHouseholdItems{}},
		// {schema: "public", entity: "household_vendors", model: generatedmodels.ModelPublicHouseholdVendors{}},
		// {schema: "public", entity: "important_dates", model: generatedmodels.ModelPublicImportantDates{}},
		{schema: "public", entity: "learnings", model: generatedmodels.ModelPublicLearnings{}},
		// {schema: "public", entity: "maintenance_logs", model: generatedmodels.ModelPublicMaintenanceLogs{}},
		// {schema: "public", entity: "maintenance_tasks", model: generatedmodels.ModelPublicMaintenanceTasks{}},
		// {schema: "public", entity: "meal_plans", model: generatedmodels.ModelPublicMealPlans{}},
		// {schema: "public", entity: "opportunities", model: generatedmodels.ModelPublicOpportunities{}},
		{schema: "public", entity: "plan_dependencies", model: generatedmodels.ModelPublicPlanDependencies{}},
		{schema: "public", entity: "plan_guardrails", model: generatedmodels.ModelPublicPlanGuardrails{}},
		{schema: "public", entity: "plan_related_plans", model: generatedmodels.ModelPublicPlanRelatedPlans{}},
		{schema: "public", entity: "plan_skills", model: generatedmodels.ModelPublicPlanSkills{}},
		{schema: "public", entity: "plans", model: generatedmodels.ModelPublicPlans{}},
		// {schema: "public", entity: "professional_contacts", model: generatedmodels.ModelPublicProfessionalContacts{}},
		{schema: "public", entity: "project_guardrails", model: generatedmodels.ModelPublicProjectGuardrails{}},
		{schema: "public", entity: "project_skills", model: generatedmodels.ModelPublicProjectSkills{}},
		{schema: "public", entity: "projects", model: generatedmodels.ModelPublicProjects{}},
		// {schema: "public", entity: "recipes", model: generatedmodels.ModelPublicRecipes{}},
		// {schema: "public", entity: "shopping_lists", model: generatedmodels.ModelPublicShoppingLists{}},
		{schema: "public", entity: "stored_files", model: generatedmodels.ModelPublicStoredFiles{}},
		{schema: "public", entity: "thought_links", model: generatedmodels.ModelPublicThoughtLinks{}},
		{schema: "public", entity: "thoughts", model: generatedmodels.ModelPublicThoughts{}},
		{schema: "public", entity: "tool_annotations", model: generatedmodels.ModelPublicToolAnnotations{}},
	}
}
