package resources_test

import (
	"testing"

	"cloud.o-forge.io/core/oc-lib/models/common/pricing"
	"cloud.o-forge.io/core/oc-lib/models/resources"
	"cloud.o-forge.io/core/oc-lib/models/utils"
	"cloud.o-forge.io/core/oc-lib/tools"
	"github.com/stretchr/testify/assert"
)

type MockInstance struct {
	ID   string
	Name string
	resources.ResourceInstance[*MockPartner]
}

func (m *MockInstance) GetID() string                  { return m.ID }
func (m *MockInstance) GetName() string                { return m.Name }
func (m *MockInstance) ClearEnv()                      {}
func (m *MockInstance) ClearPeerGroups()               {}
func (m *MockPartner) FilterPartnership(peerID string) {}
func (m *MockInstance) GetProfile(peerID string, a *int, b *int, c *int) pricing.PricingProfileITF {
	return nil
}
func (m *MockInstance) GetPricingsProfiles(peerID string, groups []string) []pricing.PricingProfileITF {
	return nil
}
func (m *MockInstance) GetPeerGroups() ([]resources.ResourcePartnerITF, []map[string][]string) {
	return nil, []map[string][]string{
		{"peer1": {"group1"}},
	}
}

type MockPartner struct {
	groups map[string][]string
}

func (m *MockPartner) GetProfile(buying *int, strategy *int) pricing.PricingProfileITF {
	return nil
}

func (m *MockPartner) GetPeerGroups() map[string][]string {
	return m.groups
}
func (m *MockPartner) ClearPeerGroups() {}

func (m *MockPartner) GetPricingsProfiles(string, []string) []pricing.PricingProfileITF {
	return nil
}

type MockDBObject struct {
	utils.AbstractObject
	isDraft bool
}

func (m *MockDBObject) IsDrafted() bool {
	return m.isDraft
}

func TestGetSelectedInstance_WithValidIndex(t *testing.T) {
	index := 1
	inst1 := &MockInstance{ID: "1"}
	inst2 := &MockInstance{ID: "2"}
	resource := &resources.AbstractInstanciatedResource[*MockInstance]{
		AbstractResource: resources.AbstractResource{},
		Instances:        []*MockInstance{inst1, inst2},
	}
	result := resource.GetSelectedInstance(&index)
	assert.Equal(t, inst2, result)
}

func TestGetSelectedInstance_NoIndex(t *testing.T) {
	inst := &MockInstance{ID: "1"}
	resource := &resources.AbstractInstanciatedResource[*MockInstance]{
		Instances: []*MockInstance{inst},
	}
	result := resource.GetSelectedInstance(nil)
	assert.Equal(t, inst, result)
}

func TestCanUpdate_WhenOnlyStateDiffers(t *testing.T) {
	resource := &resources.AbstractResource{AbstractObject: utils.AbstractObject{IsDraft: true}}
	set := &MockDBObject{isDraft: false}
	canUpdate, updated := resource.CanUpdate(set)
	assert.True(t, canUpdate)
	assert.Equal(t, set, updated)
}

func TestVerifyAuthAction_WithMatchingGroup(t *testing.T) {
	inst := &MockInstance{
		ResourceInstance: resources.ResourceInstance[*MockPartner]{
			Partnerships: []*MockPartner{
				{groups: map[string][]string{"peer1": {"group1"}}},
			},
		},
	}
	req := &tools.APIRequest{PeerID: "peer1", Groups: []string{"group1"}}
	result := resources.VerifyAuthAction([]*MockInstance{inst}, req)
	assert.Len(t, result, 1)
}

type FakeResource struct {
	resources.AbstractInstanciatedResource[*MockInstance]
}

func (f *FakeResource) SetAllowedInstances(req *tools.APIRequest, instance_id ...string) []resources.ResourceInstanceITF {
	return nil
}
func (f *FakeResource) ConvertToPricedResource(t tools.DataType, a *int, b *int, c *int, d *int, e *int, req *tools.APIRequest) (pricing.PricedItemITF, error) {
	return nil, nil
}
func (f *FakeResource) VerifyAuth(string, *tools.APIRequest) bool { return true }

func TestNewAccessor_ReturnsValid(t *testing.T) {
	acc := resources.NewAccessor[*FakeResource](tools.COMPUTE_RESOURCE, &tools.APIRequest{})
	assert.NotNil(t, acc)
}
