package maas

import (
	"context"
	"testing"

	"github.com/stretchr/testify/require"

	"github.com/tidbcloud/AgentTeam/internal/maas/availability"
	"github.com/tidbcloud/AgentTeam/internal/store/agent"
	"github.com/tidbcloud/AgentTeam/internal/store/organization"
	"github.com/tidbcloud/AgentTeam/internal/store/storeerr"
)

func TestValidateAgentBindingAcceptsAuthorizedEnabledHostedModel(t *testing.T) {
	validator := NewValidator(Dependencies{
		Organizations: fakeOrganizationStore{
			selection: organization.OrganizationHostedModelSelectionView{
				AuthorizationMode: authorizationAllActive,
			},
		},
		Availability: fakeAvailabilityClient{availability: hostedAvailabilityFixture(true, nil)},
	})

	err := validator.ValidateAgentBinding(context.Background(), AgentBindingValidation{
		OrganizationID: "org_1",
		WorkspaceID:    "wsp_1",
		ModelReference: "agentteam/deepseek-v4-pro",
		LLMMode:        agent.AgentLLMModeAgentTeamHosted,
		Features:       []string{"tool_calling"},
	})

	require.NoError(t, err)
}

func TestValidateAgentBindingRejectsDisabledHostedModelReason(t *testing.T) {
	validator := NewValidator(Dependencies{
		Organizations: fakeOrganizationStore{
			selection: organization.OrganizationHostedModelSelectionView{
				AuthorizationMode: authorizationAllActive,
			},
		},
		Availability: fakeAvailabilityClient{availability: hostedAvailabilityFixture(false, []string{ReasonZeroBalance})},
	})

	err := validator.ValidateAgentBinding(context.Background(), AgentBindingValidation{
		OrganizationID: "org_1",
		WorkspaceID:    "wsp_1",
		ModelReference: "agentteam/deepseek-v4-pro",
		LLMMode:        agent.AgentLLMModeAgentTeamHosted,
	})

	require.ErrorIs(t, err, storeerr.ErrConflict)
	require.Contains(t, err.Error(), ReasonZeroBalance)
}

func TestValidateAgentBindingRejectsWorkspaceAuthorizationAndDaemonSupport(t *testing.T) {
	t.Run("workspace authorization", func(t *testing.T) {
		validator := NewValidator(Dependencies{
			Organizations: fakeOrganizationStore{
				selection: organization.OrganizationHostedModelSelectionView{
					AuthorizationMode: authorizationSelected,
					SelectedModelRefs: []string{"agentteam/other"},
				},
			},
			Availability: fakeAvailabilityClient{availability: hostedAvailabilityFixture(true, nil)},
		})

		err := validator.ValidateAgentBinding(context.Background(), AgentBindingValidation{
			OrganizationID: "org_1",
			WorkspaceID:    "wsp_1",
			ModelReference: "agentteam/deepseek-v4-pro",
			LLMMode:        agent.AgentLLMModeAgentTeamHosted,
		})

		require.ErrorIs(t, err, storeerr.ErrConflict)
		require.Contains(t, err.Error(), ReasonWorkspaceNotAuthorized)
	})

	t.Run("daemon support", func(t *testing.T) {
		supported := false
		validator := NewValidator(Dependencies{
			Organizations: fakeOrganizationStore{},
			Availability:  fakeAvailabilityClient{},
		})

		err := validator.ValidateAgentBinding(context.Background(), AgentBindingValidation{
			OrganizationID:            "org_1",
			WorkspaceID:               "wsp_1",
			ModelReference:            "agentteam/deepseek-v4-pro",
			LLMMode:                   agent.AgentLLMModeAgentTeamHosted,
			MachineSupportsDirectMaaS: &supported,
		})

		require.ErrorIs(t, err, storeerr.ErrConflict)
		require.Contains(t, err.Error(), ReasonDaemonUpgradeRequired)
	})
}

func TestValidateAgentBindingRejectsRuntimeWireFamilyMismatch(t *testing.T) {
	availability := hostedAvailabilityFixture(true, nil)
	availability.Models[0].ExecutableWireAPIFamilies = []string{"chat_completions"}
	availability.Models[0].SupportedFamilies = []string{"chat_completions"}
	validator := NewValidator(Dependencies{
		Organizations: fakeOrganizationStore{
			selection: organization.OrganizationHostedModelSelectionView{
				AuthorizationMode: authorizationAllActive,
			},
		},
		Availability: fakeAvailabilityClient{availability: availability},
	})

	err := validator.ValidateAgentBinding(context.Background(), AgentBindingValidation{
		OrganizationID: "org_1",
		WorkspaceID:    "wsp_1",
		ModelReference: "agentteam/deepseek-v4-pro",
		LLMMode:        agent.AgentLLMModeAgentTeamHosted,
		Runtime:        "codex",
	})

	require.ErrorIs(t, err, storeerr.ErrConflict)
	require.Contains(t, err.Error(), ReasonWireFamilyUnsupported)
}

func TestValidateAgentBindingFallsBackToSupportedFamiliesForRuntimeWireFamily(t *testing.T) {
	availability := hostedAvailabilityFixture(true, nil)
	availability.Models[0].SupportedFamilies = []string{"responses"}
	validator := NewValidator(Dependencies{
		Organizations: fakeOrganizationStore{
			selection: organization.OrganizationHostedModelSelectionView{
				AuthorizationMode: authorizationAllActive,
			},
		},
		Availability: fakeAvailabilityClient{availability: availability},
	})

	err := validator.ValidateAgentBinding(context.Background(), AgentBindingValidation{
		OrganizationID: "org_1",
		WorkspaceID:    "wsp_1",
		ModelReference: "agentteam/deepseek-v4-pro",
		LLMMode:        agent.AgentLLMModeAgentTeamHosted,
		Runtime:        "codex",
	})

	require.NoError(t, err)
}

type fakeOrganizationStore struct {
	org       organization.OrganizationSummary
	selection organization.OrganizationHostedModelSelectionView
	err       error
}

func (fake fakeOrganizationStore) GetWorkspaceOrganizationForUser(context.Context, string, string) (organization.OrganizationSummary, error) {
	if fake.err != nil {
		return organization.OrganizationSummary{}, fake.err
	}
	if fake.org.ID != "" {
		return fake.org, nil
	}
	return organization.OrganizationSummary{ID: "org_1"}, nil
}

func (fake fakeOrganizationStore) GetHostedModelSelectionForWorkspace(context.Context, string, string) (organization.OrganizationHostedModelSelectionView, error) {
	if fake.err != nil {
		return organization.OrganizationHostedModelSelectionView{}, fake.err
	}
	return fake.selection, nil
}

type fakeAvailabilityClient struct {
	availability availability.Availability
	err          error
}

func (fake fakeAvailabilityClient) LoadHostedAvailability(context.Context, string) (availability.Availability, error) {
	if fake.err != nil {
		return availability.Availability{}, fake.err
	}
	return fake.availability, nil
}

func hostedAvailabilityFixture(enabled bool, reasons []string) availability.Availability {
	availability := availability.Availability{
		OrganizationID: "org_1",
		Models: []availability.Model{{
			HostedModelID:     "deepseek_v4_pro",
			ModelReference:    "agentteam/deepseek-v4-pro",
			DisplayName:       "DeepSeek V4 Pro",
			InventoryStatus:   inventoryStatusActive,
			EntitlementStatus: entitlementStatusActive,
			BalanceStatus:     balanceStatusPositive,
			RuntimeStatus:     runtimeStatusSupported,
			Enabled:           enabled,
			Reasons:           reasons,
			MessagesFeatures:  []string{"tool_calling"},
		}},
	}
	return availability
}

var _ OrganizationStore = fakeOrganizationStore{}
var _ AvailabilityClient = fakeAvailabilityClient{}
