package apply

import (
	"context"

	"edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/config"
	"edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/core/domain"
	"edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/core/ports/driven"
	"github.com/stretchr/testify/mock"
)

// MockAppRepository is a mock implementation of driven.AppRepository
type MockAppRepository struct {
	mock.Mock
}

func (m *MockAppRepository) CreateApp(ctx context.Context, region string, app *domain.App) error {
	args := m.Called(ctx, region, app)
	return args.Error(0)
}

func (m *MockAppRepository) ShowApp(ctx context.Context, region string, appKey domain.AppKey) (*domain.App, error) {
	args := m.Called(ctx, region, appKey)
	if args.Get(0) == nil {
		return nil, args.Error(1)
	}
	return args.Get(0).(*domain.App), args.Error(1)
}

func (m *MockAppRepository) ShowApps(ctx context.Context, region string, appKey domain.AppKey) ([]domain.App, error) {
	args := m.Called(ctx, region, appKey)
	if args.Get(0) == nil {
		return nil, args.Error(1)
	}
	return args.Get(0).([]domain.App), args.Error(1)
}

func (m *MockAppRepository) DeleteApp(ctx context.Context, region string, appKey domain.AppKey) error {
	args := m.Called(ctx, region, appKey)
	return args.Error(0)
}

func (m *MockAppRepository) UpdateApp(ctx context.Context, region string, app *domain.App) error {
	args := m.Called(ctx, region, app)
	return args.Error(0)
}

// MockAppInstanceRepository is a mock implementation of driven.AppInstanceRepository
type MockAppInstanceRepository struct {
	mock.Mock
}

func (m *MockAppInstanceRepository) CreateAppInstance(ctx context.Context, region string, appInst *domain.AppInstance) error {
	args := m.Called(ctx, region, appInst)
	return args.Error(0)
}

func (m *MockAppInstanceRepository) ShowAppInstance(ctx context.Context, region string, appInstKey domain.AppInstanceKey) (*domain.AppInstance, error) {
	args := m.Called(ctx, region, appInstKey)
	if args.Get(0) == nil {
		return nil, args.Error(1)
	}
	return args.Get(0).(*domain.AppInstance), args.Error(1)
}

func (m *MockAppInstanceRepository) ShowAppInstances(ctx context.Context, region string, appInstKey domain.AppInstanceKey) ([]domain.AppInstance, error) {
	args := m.Called(ctx, region, appInstKey)
	if args.Get(0) == nil {
		return nil, args.Error(1)
	}
	return args.Get(0).([]domain.AppInstance), args.Error(1)
}

func (m *MockAppInstanceRepository) DeleteAppInstance(ctx context.Context, region string, appInstKey domain.AppInstanceKey) error {
	args := m.Called(ctx, region, appInstKey)
	return args.Error(0)
}

func (m *MockAppInstanceRepository) UpdateAppInstance(ctx context.Context, region string, appInst *domain.AppInstance) error {
	args := m.Called(ctx, region, appInst)
	return args.Error(0)
}

func (m *MockAppInstanceRepository) RefreshAppInstance(ctx context.Context, region string, appInstKey domain.AppInstanceKey) error {
	args := m.Called(ctx, region, appInstKey)
	return args.Error(0)
}

// MockConfigRepository is a mock implementation of driven.ConfigRepository
type MockConfigRepository struct {
	mock.Mock
}

func (m *MockConfigRepository) ParseFile(path string) (*config.EdgeConnectConfig, string, error) {
	args := m.Called(path)
	if args.Get(0) == nil {
		return nil, args.String(1), args.Error(2)
	}
	return args.Get(0).(*config.EdgeConnectConfig), args.String(1), args.Error(2)
}

func (m *MockConfigRepository) Validate(cfg *config.EdgeConnectConfig) error {
	args := m.Called(cfg)
	return args.Error(0)
}

// NewTestPlanner creates a planner with mock repositories for testing
func NewTestPlanner(appRepo driven.AppRepository, appInstRepo driven.AppInstanceRepository) Planner {
	if appRepo == nil {
		appRepo = new(MockAppRepository)
	}
	if appInstRepo == nil {
		appInstRepo = new(MockAppInstanceRepository)
	}
	return NewPlanner(appRepo, appInstRepo)
}

// NewTestResourceManager creates a resource manager with mock repositories for testing
func NewTestResourceManager(appRepo driven.AppRepository, appInstRepo driven.AppInstanceRepository) ResourceManagerInterface {
	if appRepo == nil {
		appRepo = new(MockAppRepository)
	}
	if appInstRepo == nil {
		appInstRepo = new(MockAppInstanceRepository)
	}
	return NewResourceManager(appRepo, appInstRepo)
}

// NewTestStrategyFactory creates a strategy factory with mock repositories for testing
func NewTestStrategyFactory(appRepo driven.AppRepository, appInstRepo driven.AppInstanceRepository) *StrategyFactory {
	if appRepo == nil {
		appRepo = new(MockAppRepository)
	}
	if appInstRepo == nil {
		appInstRepo = new(MockAppInstanceRepository)
	}
	return NewStrategyFactory(appRepo, appInstRepo, DefaultStrategyConfig(), nil)
}
