package api

import (
	"encoding/json"
	"net/http"
	"testing"

	"github.com/gin-gonic/gin"
	"github.com/pingcap/dbaas/billing2/config"
	"github.com/pingcap/dbaas/billing2/forms"
	"github.com/pingcap/dbaas/billing2/utils/ginutils"
	"github.com/pingcap/dbaas/billing2/utils/tests"
)

func newRecalculateInvoiceTestRouter() *gin.Engine {
	router := gin.New()
	router.Use(ginutils.ErrorMiddleWare)
	InitializeInvoiceRouter(ginutils.MyRoute{Route: router})
	return router
}

func TestRecalculateBills(t *testing.T) {
	config.Get().Set(config.SnapshotMeteringRawTenantWhitelist, []string{"1"})
	router := newRecalculateInvoiceTestRouter()

	req := &forms.RecalculateBillsPreviewReq{
		StartDate: "2026-01-01",
		EndDate:   "2026-02-01",
	}
	w := tests.PerformRequest(router, "POST", "/tenants/1/billing_config_id/1/internal/recalculate", map[string]interface{}{})
	if w.Code != http.StatusBadRequest {
		t.Fatalf("expected status %d, got %d: %s", http.StatusBadRequest, w.Code, w.Body.String())
	}

	var applyReq forms.RecalculateBillsApplyReq
	if err := json.Unmarshal([]byte(`{"source_run_id":"1"}`), &applyReq); err != nil {
		t.Fatalf("expected source_run_id string to bind: %v", err)
	}
	if applyReq.SourceRunID != 1 {
		t.Fatalf("expected source_run_id 1, got %d", applyReq.SourceRunID)
	}

	w = tests.PerformRequest(router, "POST", "/tenants/1/billing_config_id/1/recalculate", map[string]string{
		"start_date": "2026-01-01",
	})
	if w.Code != http.StatusBadRequest {
		t.Fatalf("expected status %d, got %d: %s", http.StatusBadRequest, w.Code, w.Body.String())
	}

	w = tests.PerformRequest(router, "POST", "/tenants/2/billing_config_id/1/recalculate", req)
	if w.Code != http.StatusForbidden {
		t.Fatalf("expected status %d, got %d: %s", http.StatusForbidden, w.Code, w.Body.String())
	}

	w = tests.PerformRequest(router, "POST", "/tenants/2/billing_config_id/1/internal/recalculate", map[string]string{
		"source_run_id": "999",
	})
	if w.Code != http.StatusOK {
		t.Fatalf("expected status %d, got %d: %s", http.StatusOK, w.Code, w.Body.String())
	}
	var skipped map[string]string
	if err := json.Unmarshal(w.Body.Bytes(), &skipped); err != nil {
		t.Fatalf("unmarshal skipped response: %v", err)
	}
	if skipped["status"] != "skipped" {
		t.Fatalf("expected skipped response, got %s", w.Body.String())
	}
}

func TestRecalculateInvoice(t *testing.T) {
	config.Get().Set(config.SnapshotMeteringRawTenantWhitelist, []string{"1"})
	router := newRecalculateInvoiceTestRouter()

	w := tests.PerformRequest(router, "POST", "/tenants/1/billing_config_id/1/invoices/1/internal/recalculate", nil)
	if w.Code != http.StatusNotFound {
		t.Fatalf("expected status %d, got %d: %s", http.StatusNotFound, w.Code, w.Body.String())
	}
}
