package org

import (
	"context"
	"net/http/httptest"
	"testing"
	"time"

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

	"github.com/tidbcloud/AgentTeam/internal/api"
	"github.com/tidbcloud/AgentTeam/internal/knowledgeqa/protocol"
	"github.com/tidbcloud/AgentTeam/internal/store/identity"
	"github.com/tidbcloud/AgentTeam/internal/store/organization"
)

type knowledgeQAPolicyOrganizationProvider struct {
	OrganizationProvider
	role string
}

func (provider knowledgeQAPolicyOrganizationProvider) RequireOrganizationAdmin(context.Context, string, string) error {
	if provider.role != "org_owner" && provider.role != "org_admin" {
		return organization.ErrForbidden
	}
	return nil
}

type fakeOrganizationKnowledgeQAPolicies struct {
	organization protocol.OrganizationPolicy
	updated      protocol.OrganizationPolicyUpdate
	metricsLoads int
}

func (fake *fakeOrganizationKnowledgeQAPolicies) LoadPolicyMetrics(context.Context, string) (protocol.PolicyMetrics, error) {
	fake.metricsLoads++
	return protocol.PolicyMetrics{WindowDays: 30, TotalTurns: 4, NoAnswerTurns: 1}, nil
}

func (fake *fakeOrganizationKnowledgeQAPolicies) LoadOrganizationPolicy(context.Context, string) (protocol.OrganizationPolicy, error) {
	return fake.organization, nil
}

func (fake *fakeOrganizationKnowledgeQAPolicies) UpdateOrganizationPolicy(_ context.Context, _, _ string, update protocol.OrganizationPolicyUpdate, _ time.Time) (protocol.OrganizationPolicy, error) {
	fake.updated = update
	fake.organization.Enabled = update.Enabled
	return fake.organization, nil
}

func TestOrganizationKnowledgeQAPolicyGetRequiresOrganizationAdmin(t *testing.T) {
	handler := &KnowledgeQAPolicyHandler{organizationHandlerBase: organizationHandlerBase{
		organizations:       knowledgeQAPolicyOrganizationProvider{role: "org_member"},
		knowledgeQAPolicies: &fakeOrganizationKnowledgeQAPolicies{},
	}}
	_, err := handler.Get(organizationKnowledgeQATestRequest("usr_1", "org_1"))
	require.Error(t, err)
	var httpErr api.HTTPError
	require.ErrorAs(t, err, &httpErr)
	require.Equal(t, 403, httpErr.Status)
	require.Equal(t, "knowledge_qa_policy_forbidden", httpErr.Code)
}

func TestOrganizationKnowledgeQAPolicyReturnsOnlySwitch(t *testing.T) {
	policies := &fakeOrganizationKnowledgeQAPolicies{organization: protocol.OrganizationPolicy{
		OrganizationID: "org_1", Enabled: true, PolicyVersion: 2,
	}}
	handler := &KnowledgeQAPolicyHandler{organizationHandlerBase: organizationHandlerBase{
		organizations:       knowledgeQAPolicyOrganizationProvider{role: "org_admin"},
		knowledgeQAPolicies: policies,
	}}
	response, err := handler.Get(organizationKnowledgeQATestRequest("usr_1", "org_1"))
	require.NoError(t, err)
	require.Equal(t, 200, response.Status)
	body := response.Body.(organizationKnowledgeQAPolicyResponse)
	require.Equal(t, "enabled", body.Status)
	require.True(t, body.Policy.Enabled)
	require.Zero(t, policies.metricsLoads)
}

func TestOrganizationKnowledgeQAPolicyMetricsLoadExplicitly(t *testing.T) {
	policies := &fakeOrganizationKnowledgeQAPolicies{}
	handler := &KnowledgeQAPolicyHandler{organizationHandlerBase: organizationHandlerBase{
		organizations:       knowledgeQAPolicyOrganizationProvider{role: "org_admin"},
		knowledgeQAPolicies: policies,
	}}
	response, err := handler.Metrics(organizationKnowledgeQATestRequest("usr_1", "org_1"))
	require.NoError(t, err)
	require.Equal(t, 200, response.Status)
	metrics := response.Body.(protocol.PolicyMetrics)
	require.Equal(t, int64(30), metrics.WindowDays)
	require.Equal(t, int64(4), metrics.TotalTurns)
	require.Equal(t, 1, policies.metricsLoads)
}

func organizationKnowledgeQATestRequest(userID, organizationID string) api.AuthenticatedRequest {
	ctx, _ := gin.CreateTestContext(httptest.NewRecorder())
	ctx.Params = gin.Params{{Key: "orgId", Value: organizationID}}
	return api.AuthenticatedRequest{
		Gin:  ctx,
		User: identity.AuthenticatedUser{User: identity.User{ID: userID}},
	}
}
