package reports

import (
	"bytes"
	"context"
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"testing"
	"time"

	"github.com/TaruLab/keluargamart-backend/internal/auth"
	"github.com/go-chi/chi/v5"
)

type memorySettingsStore struct {
	Store
	settings map[string][]byte
}

func newMemorySettingsStore() *memorySettingsStore {
	return &memorySettingsStore{
		settings: make(map[string][]byte),
	}
}

func (m *memorySettingsStore) GetAppSetting(ctx context.Context, key string) ([]byte, error) {
	val, ok := m.settings[key]
	if !ok {
		return nil, nil
	}
	return val, nil
}

func (m *memorySettingsStore) UpsertAppSetting(ctx context.Context, key string, val []byte) error {
	m.settings[key] = val
	return nil
}

func (m *memorySettingsStore) DeleteAppSetting(ctx context.Context, key string) error {
	delete(m.settings, key)
	return nil
}

func TestWidgetPolicyAndPreferences(t *testing.T) {
	memStore := newMemorySettingsStore()
	svc := NewService(memStore, time.UTC)
	handler := NewHandler(svc)

	// 1. GetWidgetPolicy returns defaults
	req := httptest.NewRequest(http.MethodGet, "/dashboard/widgets/policy", nil)
	rec := httptest.NewRecorder()
	handler.GetWidgetPolicy(rec, req)
	if rec.Code != http.StatusOK {
		t.Fatalf("Expected 200, got %d", rec.Code)
	}

	var resp struct {
		Data map[string][]string `json:"data"`
	}
	if err := json.Unmarshal(rec.Body.Bytes(), &resp); err != nil {
		t.Fatalf("Failed to unmarshal response: %v", err)
	}
	if len(resp.Data["admin"]) == 0 {
		t.Errorf("Expected admin widgets, got empty")
	}

	// 2. SetRoleWidgetPolicy
	newAdminWidgets := []string{"revenue-trend", "cashflow"}
	body, _ := json.Marshal(map[string]any{"widgets": newAdminWidgets})
	rContext := chi.NewRouteContext()
	rContext.URLParams.Add("role", "admin")

	reqSet := httptest.NewRequest(http.MethodPut, "/dashboard/widgets/policy/admin", bytes.NewReader(body))
	reqSet = reqSet.WithContext(context.WithValue(reqSet.Context(), chi.RouteCtxKey, rContext))
	recSet := httptest.NewRecorder()
	handler.SetRoleWidgetPolicy(recSet, reqSet)
	if recSet.Code != http.StatusOK {
		t.Fatalf("Expected 200 on SetRoleWidgetPolicy, got %d: %s", recSet.Code, recSet.Body.String())
	}

	// 3. User Preferences for an authenticated user
	testUser := &auth.User{
		ID:   99,
		Name: "Test Operator",
		Role: auth.RoleAdmin,
	}
	ctxWithUser := auth.ToContext(context.Background(), testUser, 1)

	// Get initial preferences (should reflect updated admin policy)
	reqPref := httptest.NewRequest(http.MethodGet, "/dashboard/widgets/preferences", nil).WithContext(ctxWithUser)
	recPref := httptest.NewRecorder()
	handler.GetUserWidgetPreferences(recPref, reqPref)
	if recPref.Code != http.StatusOK {
		t.Fatalf("Expected 200 on GetUserWidgetPreferences, got %d", recPref.Code)
	}
	var prefResp struct {
		Data UserWidgetPreference `json:"data"`
	}
	_ = json.Unmarshal(recPref.Body.Bytes(), &prefResp)
	if len(prefResp.Data.Widgets) != 2 {
		t.Errorf("Expected 2 admin widgets from policy, got %d", len(prefResp.Data.Widgets))
	}

	// Custom personal preferences
	customPref := UserWidgetPreference{
		Widgets: []string{"revenue-trend"},
		Order:   []string{"revenue-trend"},
	}
	prefBody, _ := json.Marshal(customPref)
	reqSetPref := httptest.NewRequest(http.MethodPut, "/dashboard/widgets/preferences", bytes.NewReader(prefBody)).WithContext(ctxWithUser)
	recSetPref := httptest.NewRecorder()
	handler.SetUserWidgetPreferences(recSetPref, reqSetPref)
	if recSetPref.Code != http.StatusOK {
		t.Fatalf("Expected 200 on SetUserWidgetPreferences, got %d", recSetPref.Code)
	}

	// Reset preferences
	reqReset := httptest.NewRequest(http.MethodPost, "/dashboard/widgets/preferences/reset", nil).WithContext(ctxWithUser)
	recReset := httptest.NewRecorder()
	handler.ResetUserWidgetPreferences(recReset, reqReset)
	if recReset.Code != http.StatusOK {
		t.Fatalf("Expected 200 on ResetUserWidgetPreferences, got %d", recReset.Code)
	}
}
