package dashboard

import (
	"encoding/json"
	"errors"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/gofiber/fiber/v2"
)

type dashboardServiceMock struct {
	stats map[string]interface{}
	err   error

	calls      int
	lastBranch uint
	lastRole   string
}

func (m *dashboardServiceMock) GetDashboardStats(branchID uint, role string) (map[string]interface{}, error) {
	m.calls++
	m.lastBranch = branchID
	m.lastRole = role
	if m.err != nil {
		return nil, m.err
	}
	return m.stats, nil
}

func (m *dashboardServiceMock) GetAlerts(branchID uint, role string) ([]map[string]interface{}, error) {
	return nil, nil
}

func buildDashboardHandlerTestApp(h *Handler, setLocals bool, branchID uint, role string) *fiber.App {
	app := fiber.New()
	if setLocals {
		app.Use(func(c *fiber.Ctx) error {
			c.Locals("current_branch_id", branchID)
			c.Locals("role", role)
			return c.Next()
		})
	}
	app.Get("/dashboard/stats", h.GetStats)
	return app
}

func decodeDashboardBody(t *testing.T, resp *http.Response) map[string]interface{} {
	t.Helper()
	var body map[string]interface{}
	if err := json.NewDecoder(resp.Body).Decode(&body); err != nil {
		t.Fatalf("decode response failed: %v", err)
	}
	return body
}

func TestGetStatsReturnsSuccessAndDelegatesContext(t *testing.T) {
	svc := &dashboardServiceMock{stats: map[string]interface{}{"total_users": 10, "active_jobs": 2}}
	h := NewHandler(svc)
	app := buildDashboardHandlerTestApp(h, true, 7, "admin")

	req := httptest.NewRequest(http.MethodGet, "/dashboard/stats", nil)
	resp, err := app.Test(req)
	if err != nil {
		t.Fatalf("request failed: %v", err)
	}
	if resp.StatusCode != fiber.StatusOK {
		t.Fatalf("expected %d, got %d", fiber.StatusOK, resp.StatusCode)
	}

	if svc.calls != 1 || svc.lastBranch != 7 || svc.lastRole != "admin" {
		t.Fatalf("unexpected service call args calls=%d branch=%d role=%q", svc.calls, svc.lastBranch, svc.lastRole)
	}

	body := decodeDashboardBody(t, resp)
	if body["success"] != true {
		t.Fatalf("expected success=true, got=%v", body["success"])
	}
	data, ok := body["data"].(map[string]interface{})
	if !ok {
		t.Fatalf("expected object data payload, got=%T", body["data"])
	}
	if data["total_users"] != float64(10) || data["active_jobs"] != float64(2) {
		t.Fatalf("unexpected data payload: %+v", data)
	}
}

func TestGetStatsReturnsInternalErrorWhenServiceFails(t *testing.T) {
	svc := &dashboardServiceMock{err: errors.New("db unavailable")}
	h := NewHandler(svc)
	app := buildDashboardHandlerTestApp(h, true, 1, "user")

	req := httptest.NewRequest(http.MethodGet, "/dashboard/stats", nil)
	resp, err := app.Test(req)
	if err != nil {
		t.Fatalf("request failed: %v", err)
	}
	if resp.StatusCode != fiber.StatusInternalServerError {
		t.Fatalf("expected %d, got %d", fiber.StatusInternalServerError, resp.StatusCode)
	}
	if svc.calls != 1 {
		t.Fatalf("expected one service call, got=%d", svc.calls)
	}
}

func TestGetStatsUsesZeroBranchAndEmptyRoleWhenLocalsMissing(t *testing.T) {
	svc := &dashboardServiceMock{stats: map[string]interface{}{"total_users": 0}}
	h := NewHandler(svc)
	app := buildDashboardHandlerTestApp(h, false, 0, "")

	req := httptest.NewRequest(http.MethodGet, "/dashboard/stats", nil)
	resp, err := app.Test(req)
	if err != nil {
		t.Fatalf("request failed: %v", err)
	}
	if resp.StatusCode != fiber.StatusOK {
		t.Fatalf("expected %d, got %d", fiber.StatusOK, resp.StatusCode)
	}
	if svc.lastBranch != 0 || svc.lastRole != "" {
		t.Fatalf("expected zero-value context forwarding, got branch=%d role=%q", svc.lastBranch, svc.lastRole)
	}
}
