package sync

import (
	"context"
	"fmt"

	"go.uber.org/zap"

	"codeberg.org/mapleopentech/monorepo/native/desktop/maplefile/internal/domain/syncstate"
)

// Service provides unified sync operations
type Service interface {
	// SyncAll synchronizes both collections and files
	SyncAll(ctx context.Context, input *SyncInput) (*SyncResult, error)

	// SyncCollections synchronizes collections only
	SyncCollections(ctx context.Context, input *SyncInput) (*SyncResult, error)

	// SyncFiles synchronizes files only
	SyncFiles(ctx context.Context, input *SyncInput) (*SyncResult, error)

	// GetSyncStatus returns the current sync status
	GetSyncStatus(ctx context.Context) (*SyncStatus, error)

	// ResetSync resets all sync state for a fresh sync
	ResetSync(ctx context.Context) error
}

type service struct {
	logger         *zap.Logger
	collectionSync CollectionSyncService
	fileSync       FileSyncService
	repoProvider   RepositoryProvider
}

// ProvideService creates a new unified sync service for Wire
func ProvideService(
	logger *zap.Logger,
	collectionSync CollectionSyncService,
	fileSync FileSyncService,
	repoProvider RepositoryProvider,
) Service {
	return &service{
		logger:         logger.Named("SyncService"),
		collectionSync: collectionSync,
		fileSync:       fileSync,
		repoProvider:   repoProvider,
	}
}

// getSyncStateRepo returns the sync state repository, or an error if not initialized
func (s *service) getSyncStateRepo() (syncstate.Repository, error) {
	if !s.repoProvider.IsInitialized() {
		return nil, fmt.Errorf("storage not initialized - user must be logged in")
	}
	repo := s.repoProvider.GetSyncStateRepository()
	if repo == nil {
		return nil, fmt.Errorf("sync state repository not available")
	}
	return repo, nil
}

// SyncAll synchronizes both collections and files
func (s *service) SyncAll(ctx context.Context, input *SyncInput) (*SyncResult, error) {
	s.logger.Info("Starting full sync (collections + files)")

	// Sync collections first
	colResult, err := s.collectionSync.Execute(ctx, input)
	if err != nil {
		s.logger.Error("Collection sync failed during full sync", zap.Error(err))
		return nil, err
	}

	// Sync files
	fileResult, err := s.fileSync.Execute(ctx, input)
	if err != nil {
		s.logger.Error("File sync failed during full sync", zap.Error(err))
		// Return partial result with collection data
		return &SyncResult{
			CollectionsProcessed: colResult.CollectionsProcessed,
			CollectionsAdded:     colResult.CollectionsAdded,
			CollectionsUpdated:   colResult.CollectionsUpdated,
			CollectionsDeleted:   colResult.CollectionsDeleted,
			Errors:               append(colResult.Errors, "file sync failed: "+err.Error()),
		}, err
	}

	// Merge results
	result := &SyncResult{
		CollectionsProcessed: colResult.CollectionsProcessed,
		CollectionsAdded:     colResult.CollectionsAdded,
		CollectionsUpdated:   colResult.CollectionsUpdated,
		CollectionsDeleted:   colResult.CollectionsDeleted,
		FilesProcessed:       fileResult.FilesProcessed,
		FilesAdded:           fileResult.FilesAdded,
		FilesUpdated:         fileResult.FilesUpdated,
		FilesDeleted:         fileResult.FilesDeleted,
		Errors:               append(colResult.Errors, fileResult.Errors...),
	}

	s.logger.Info("Full sync completed",
		zap.Int("collections_processed", result.CollectionsProcessed),
		zap.Int("files_processed", result.FilesProcessed),
		zap.Int("errors", len(result.Errors)))

	return result, nil
}

// SyncCollections synchronizes collections only
func (s *service) SyncCollections(ctx context.Context, input *SyncInput) (*SyncResult, error) {
	return s.collectionSync.Execute(ctx, input)
}

// SyncFiles synchronizes files only
func (s *service) SyncFiles(ctx context.Context, input *SyncInput) (*SyncResult, error) {
	return s.fileSync.Execute(ctx, input)
}

// GetSyncStatus returns the current sync status
func (s *service) GetSyncStatus(ctx context.Context) (*SyncStatus, error) {
	syncStateRepo, err := s.getSyncStateRepo()
	if err != nil {
		return nil, err
	}

	state, err := syncStateRepo.Get()
	if err != nil {
		return nil, err
	}

	return &SyncStatus{
		CollectionsSynced: state.IsCollectionSyncComplete(),
		FilesSynced:       state.IsFileSyncComplete(),
		FullySynced:       state.IsFullySynced(),
	}, nil
}

// ResetSync resets all sync state for a fresh sync
func (s *service) ResetSync(ctx context.Context) error {
	s.logger.Info("Resetting sync state")

	syncStateRepo, err := s.getSyncStateRepo()
	if err != nil {
		return err
	}

	return syncStateRepo.Reset()
}
