package mocks

import (
	"context"

	"github.com/stretchr/testify/mock"

	accountEntities "github.com/rwadurian/mpc-system/services/account/domain/entities"
	accountVO "github.com/rwadurian/mpc-system/services/account/domain/value_objects"
	sessionEntities "github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities"
	sessionVO "github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects"
)

// MockSessionRepository is a mock implementation of SessionRepository
type MockSessionRepository struct {
	mock.Mock
}

func (m *MockSessionRepository) Create(ctx context.Context, session *sessionEntities.MPCSession) error {
	args := m.Called(ctx, session)
	return args.Error(0)
}

func (m *MockSessionRepository) GetByID(ctx context.Context, id sessionVO.SessionID) (*sessionEntities.MPCSession, error) {
	args := m.Called(ctx, id)
	if args.Get(0) == nil {
		return nil, args.Error(1)
	}
	return args.Get(0).(*sessionEntities.MPCSession), args.Error(1)
}

func (m *MockSessionRepository) Update(ctx context.Context, session *sessionEntities.MPCSession) error {
	args := m.Called(ctx, session)
	return args.Error(0)
}

func (m *MockSessionRepository) Delete(ctx context.Context, id sessionVO.SessionID) error {
	args := m.Called(ctx, id)
	return args.Error(0)
}

func (m *MockSessionRepository) ListActive(ctx context.Context, limit, offset int) ([]*sessionEntities.MPCSession, error) {
	args := m.Called(ctx, limit, offset)
	if args.Get(0) == nil {
		return nil, args.Error(1)
	}
	return args.Get(0).([]*sessionEntities.MPCSession), args.Error(1)
}

func (m *MockSessionRepository) GetExpired(ctx context.Context, limit int) ([]*sessionEntities.MPCSession, error) {
	args := m.Called(ctx, limit)
	if args.Get(0) == nil {
		return nil, args.Error(1)
	}
	return args.Get(0).([]*sessionEntities.MPCSession), args.Error(1)
}

func (m *MockSessionRepository) AddParticipant(ctx context.Context, participant *sessionEntities.Participant) error {
	args := m.Called(ctx, participant)
	return args.Error(0)
}

func (m *MockSessionRepository) UpdateParticipant(ctx context.Context, participant *sessionEntities.Participant) error {
	args := m.Called(ctx, participant)
	return args.Error(0)
}

func (m *MockSessionRepository) GetParticipant(ctx context.Context, sessionID sessionVO.SessionID, partyID sessionVO.PartyID) (*sessionEntities.Participant, error) {
	args := m.Called(ctx, sessionID, partyID)
	if args.Get(0) == nil {
		return nil, args.Error(1)
	}
	return args.Get(0).(*sessionEntities.Participant), args.Error(1)
}

// MockAccountRepository is a mock implementation of AccountRepository
type MockAccountRepository struct {
	mock.Mock
}

func (m *MockAccountRepository) Create(ctx context.Context, account *accountEntities.Account) error {
	args := m.Called(ctx, account)
	return args.Error(0)
}

func (m *MockAccountRepository) GetByID(ctx context.Context, id accountVO.AccountID) (*accountEntities.Account, error) {
	args := m.Called(ctx, id)
	if args.Get(0) == nil {
		return nil, args.Error(1)
	}
	return args.Get(0).(*accountEntities.Account), args.Error(1)
}

func (m *MockAccountRepository) GetByUsername(ctx context.Context, username string) (*accountEntities.Account, error) {
	args := m.Called(ctx, username)
	if args.Get(0) == nil {
		return nil, args.Error(1)
	}
	return args.Get(0).(*accountEntities.Account), args.Error(1)
}

func (m *MockAccountRepository) GetByEmail(ctx context.Context, email string) (*accountEntities.Account, error) {
	args := m.Called(ctx, email)
	if args.Get(0) == nil {
		return nil, args.Error(1)
	}
	return args.Get(0).(*accountEntities.Account), args.Error(1)
}

func (m *MockAccountRepository) GetByPublicKey(ctx context.Context, publicKey []byte) (*accountEntities.Account, error) {
	args := m.Called(ctx, publicKey)
	if args.Get(0) == nil {
		return nil, args.Error(1)
	}
	return args.Get(0).(*accountEntities.Account), args.Error(1)
}

func (m *MockAccountRepository) Update(ctx context.Context, account *accountEntities.Account) error {
	args := m.Called(ctx, account)
	return args.Error(0)
}

func (m *MockAccountRepository) Delete(ctx context.Context, id accountVO.AccountID) error {
	args := m.Called(ctx, id)
	return args.Error(0)
}

func (m *MockAccountRepository) ExistsByUsername(ctx context.Context, username string) (bool, error) {
	args := m.Called(ctx, username)
	return args.Bool(0), args.Error(1)
}

func (m *MockAccountRepository) ExistsByEmail(ctx context.Context, email string) (bool, error) {
	args := m.Called(ctx, email)
	return args.Bool(0), args.Error(1)
}

func (m *MockAccountRepository) List(ctx context.Context, offset, limit int) ([]*accountEntities.Account, error) {
	args := m.Called(ctx, offset, limit)
	if args.Get(0) == nil {
		return nil, args.Error(1)
	}
	return args.Get(0).([]*accountEntities.Account), args.Error(1)
}

func (m *MockAccountRepository) Count(ctx context.Context) (int64, error) {
	args := m.Called(ctx)
	return args.Get(0).(int64), args.Error(1)
}

// MockAccountShareRepository is a mock implementation of AccountShareRepository
type MockAccountShareRepository struct {
	mock.Mock
}

func (m *MockAccountShareRepository) Create(ctx context.Context, share *accountEntities.AccountShare) error {
	args := m.Called(ctx, share)
	return args.Error(0)
}

func (m *MockAccountShareRepository) GetByID(ctx context.Context, id string) (*accountEntities.AccountShare, error) {
	args := m.Called(ctx, id)
	if args.Get(0) == nil {
		return nil, args.Error(1)
	}
	return args.Get(0).(*accountEntities.AccountShare), args.Error(1)
}

func (m *MockAccountShareRepository) GetByAccountID(ctx context.Context, accountID accountVO.AccountID) ([]*accountEntities.AccountShare, error) {
	args := m.Called(ctx, accountID)
	if args.Get(0) == nil {
		return nil, args.Error(1)
	}
	return args.Get(0).([]*accountEntities.AccountShare), args.Error(1)
}

func (m *MockAccountShareRepository) GetActiveByAccountID(ctx context.Context, accountID accountVO.AccountID) ([]*accountEntities.AccountShare, error) {
	args := m.Called(ctx, accountID)
	if args.Get(0) == nil {
		return nil, args.Error(1)
	}
	return args.Get(0).([]*accountEntities.AccountShare), args.Error(1)
}

func (m *MockAccountShareRepository) GetByPartyID(ctx context.Context, partyID string) ([]*accountEntities.AccountShare, error) {
	args := m.Called(ctx, partyID)
	if args.Get(0) == nil {
		return nil, args.Error(1)
	}
	return args.Get(0).([]*accountEntities.AccountShare), args.Error(1)
}

func (m *MockAccountShareRepository) Update(ctx context.Context, share *accountEntities.AccountShare) error {
	args := m.Called(ctx, share)
	return args.Error(0)
}

func (m *MockAccountShareRepository) Delete(ctx context.Context, id string) error {
	args := m.Called(ctx, id)
	return args.Error(0)
}

func (m *MockAccountShareRepository) DeactivateByAccountID(ctx context.Context, accountID accountVO.AccountID) error {
	args := m.Called(ctx, accountID)
	return args.Error(0)
}

func (m *MockAccountShareRepository) DeactivateByShareType(ctx context.Context, accountID accountVO.AccountID, shareType accountVO.ShareType) error {
	args := m.Called(ctx, accountID, shareType)
	return args.Error(0)
}

// MockEventPublisher is a mock implementation for event publishing
type MockEventPublisher struct {
	mock.Mock
}

func (m *MockEventPublisher) Publish(ctx context.Context, event interface{}) error {
	args := m.Called(ctx, event)
	return args.Error(0)
}

func (m *MockEventPublisher) Close() error {
	args := m.Called()
	return args.Error(0)
}

// MockTokenService is a mock implementation of TokenService
type MockTokenService struct {
	mock.Mock
}

func (m *MockTokenService) GenerateAccessToken(accountID, username string) (string, error) {
	args := m.Called(accountID, username)
	return args.String(0), args.Error(1)
}

func (m *MockTokenService) GenerateRefreshToken(accountID string) (string, error) {
	args := m.Called(accountID)
	return args.String(0), args.Error(1)
}

func (m *MockTokenService) ValidateAccessToken(token string) (map[string]interface{}, error) {
	args := m.Called(token)
	if args.Get(0) == nil {
		return nil, args.Error(1)
	}
	return args.Get(0).(map[string]interface{}), args.Error(1)
}

func (m *MockTokenService) ValidateRefreshToken(token string) (string, error) {
	args := m.Called(token)
	return args.String(0), args.Error(1)
}

func (m *MockTokenService) RefreshAccessToken(refreshToken string) (string, error) {
	args := m.Called(refreshToken)
	return args.String(0), args.Error(1)
}

// MockCacheService is a mock implementation of CacheService
type MockCacheService struct {
	mock.Mock
}

func (m *MockCacheService) Set(ctx context.Context, key string, value interface{}, ttlSeconds int) error {
	args := m.Called(ctx, key, value, ttlSeconds)
	return args.Error(0)
}

func (m *MockCacheService) Get(ctx context.Context, key string) (interface{}, error) {
	args := m.Called(ctx, key)
	return args.Get(0), args.Error(1)
}

func (m *MockCacheService) Delete(ctx context.Context, key string) error {
	args := m.Called(ctx, key)
	return args.Error(0)
}

func (m *MockCacheService) Exists(ctx context.Context, key string) (bool, error) {
	args := m.Called(ctx, key)
	return args.Bool(0), args.Error(1)
}
