package org_test

import (
	"log/slog"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/gin-gonic/gin"
	"github.com/stretchr/testify/require"

	"github.com/tidbcloud/AgentTeam/internal/api/dto"
	. "github.com/tidbcloud/AgentTeam/internal/api/testkit"
	"github.com/tidbcloud/AgentTeam/internal/coredb"
	"github.com/tidbcloud/AgentTeam/internal/mailer"
	"github.com/tidbcloud/AgentTeam/internal/store/organization"
	"github.com/tidbcloud/AgentTeam/internal/store/plan"
	"github.com/tidbcloud/AgentTeam/internal/store/seatbilling"
)

func TestOrganizationPlanViewUsesSeatEntitlementQuota(t *testing.T) {
	t.Parallel()

	runtime := StartRuntimeWithOrganizationProvider(t, false, 30, func(logger *slog.Logger) mailer.Mailer {
		return mailer.NewNoop(logger, "http://localhost:3001")
	}, func(pool coredb.DB, dataStore *Store) OrganizationProvider {
		return organization.NewWithDBOptions(pool, NewOrganizationCoreBridge(pool, dataStore), organization.ServiceOptions{})
	})

	router := gin.New()
	runtime.RegisterRoutes(router)
	server := httptest.NewServer(router)
	defer server.Close()

	client := server.Client()

	var adminAuth dto.AuthTokensResponse
	response := DoJSON(t, client, http.MethodPost, server.URL+"/api/v1/auth/register", map[string]any{
		"email":    "plan-admin@example.com",
		"password": TestUserPassword,
		"name":     "plan-admin",
	}, nil, &adminAuth)
	require.Equal(t, http.StatusOK, response.StatusCode)
	require.True(t, adminAuth.User.IsAdmin)

	organizationSummary := FirstOrganizationForTests(t, client, server.URL, adminAuth.AccessToken)

	var planView dto.OrganizationPlanView
	response = DoJSON(t, client, http.MethodGet, server.URL+"/api/v1/orgs/"+organizationSummary.ID+"/plan", nil, AuthHeaders(adminAuth.AccessToken), &planView)
	require.Equal(t, http.StatusOK, response.StatusCode)
	require.Equal(t, string(plan.PlanFree), planView.PlanKey)
	require.Equal(t, "active", planView.Status)
	require.EqualValues(t, seatbilling.FreeHumanSeatLimit, planView.Limits[string(plan.MetricSeats)])
	require.EqualValues(t, seatbilling.FreeAgentsPerHumanOwnerLimit, planView.Limits[string(plan.MetricAgents)])
	require.EqualValues(t, 1, planView.Usage[string(plan.MetricSeats)])
	require.NotContains(t, planView.Limits, string(plan.MetricWorkspaces))
	require.NotContains(t, planView.Limits, string(plan.MetricMachines))
	require.NotContains(t, planView.Limits, string(plan.MetricChannels))

	var workspace dto.WorkspaceResponse
	response = DoJSON(t, client, http.MethodPost, server.URL+"/api/v1/workspaces", map[string]any{
		"organizationId": organizationSummary.ID,
		"name":           "Allowed Workspace",
		"slug":           "allowed-workspace",
	}, AuthHeaders(adminAuth.AccessToken), &workspace)
	require.Equal(t, http.StatusOK, response.StatusCode)
	require.Empty(t, workspace.Plan)

	var usage dto.WorkspaceUsageView
	response = DoJSON(t, client, http.MethodGet, server.URL+"/api/v1/workspaces/"+workspace.ID+"/usage", nil, AuthHeaders(adminAuth.AccessToken), &usage)
	require.Equal(t, http.StatusOK, response.StatusCode)
	require.Equal(t, string(plan.PlanFree), usage.Organization.PlanKey)
	require.EqualValues(t, seatbilling.FreeHumanSeatLimit, usage.Organization.Limits[string(plan.MetricSeats)])
	require.EqualValues(t, seatbilling.FreeAgentsPerHumanOwnerLimit, usage.Organization.Limits[string(plan.MetricAgents)])
	require.EqualValues(t, 0, usage.MachineCount)
	require.EqualValues(t, 0, usage.AgentCount)
	require.EqualValues(t, 0, usage.ChannelCount)
}
