package app

import (
	"fmt"
	"time"

	"go.uber.org/zap"

	"codeberg.org/mapleopentech/monorepo/native/desktop/maplefile/internal/service/sync"
)

// SyncStatusData represents the current sync status for the frontend
type SyncStatusData struct {
	IsSyncing         bool   `json:"is_syncing"`
	LastSyncTime      string `json:"last_sync_time,omitempty"`
	LastSyncSuccess   bool   `json:"last_sync_success"`
	LastSyncError     string `json:"last_sync_error,omitempty"`
	CollectionsSynced bool   `json:"collections_synced"`
	FilesSynced       bool   `json:"files_synced"`
	FullySynced       bool   `json:"fully_synced"`
}

// SyncResultData represents the result of a sync operation
type SyncResultData struct {
	CollectionsProcessed int      `json:"collections_processed"`
	CollectionsAdded     int      `json:"collections_added"`
	CollectionsUpdated   int      `json:"collections_updated"`
	CollectionsDeleted   int      `json:"collections_deleted"`
	FilesProcessed       int      `json:"files_processed"`
	FilesAdded           int      `json:"files_added"`
	FilesUpdated         int      `json:"files_updated"`
	FilesDeleted         int      `json:"files_deleted"`
	Errors               []string `json:"errors,omitempty"`
}

// GetSyncStatus returns the current sync status
func (a *Application) GetSyncStatus() (*SyncStatusData, error) {
	status, err := a.syncService.GetSyncStatus(a.ctx)
	if err != nil {
		a.logger.Error("Failed to get sync status", zap.Error(err))
		return nil, fmt.Errorf("failed to get sync status: %w", err)
	}

	return &SyncStatusData{
		IsSyncing:         false,
		LastSyncTime:      time.Now().Format(time.RFC3339),
		LastSyncSuccess:   true,
		LastSyncError:     "",
		CollectionsSynced: status.CollectionsSynced,
		FilesSynced:       status.FilesSynced,
		FullySynced:       status.FullySynced,
	}, nil
}

// TriggerSync triggers a full sync of collections and files
func (a *Application) TriggerSync() error {
	a.logger.Info("Manual sync triggered")

	// Get current session for email
	session, err := a.authService.GetCurrentSession(a.ctx)
	if err != nil {
		a.logger.Error("Failed to get session for sync", zap.Error(err))
		return fmt.Errorf("not authenticated: %w", err)
	}

	// Get the stored password for decryption
	var password string
	if a.passwordStore.HasPassword(session.Email) {
		password, err = a.passwordStore.GetPassword(session.Email)
		if err != nil {
			a.logger.Warn("Failed to get stored password, sync will skip decryption", zap.Error(err))
		}
	} else {
		a.logger.Warn("No stored password, sync will skip decryption")
	}

	input := &sync.SyncInput{
		BatchSize:  50,
		MaxBatches: 100,
		Password:   password,
	}

	result, err := a.syncService.SyncAll(a.ctx, input)
	if err != nil {
		a.logger.Error("Sync failed", zap.Error(err))
		return fmt.Errorf("sync failed: %w", err)
	}

	a.logger.Info("Sync completed",
		zap.Int("collections_added", result.CollectionsAdded),
		zap.Int("files_added", result.FilesAdded),
		zap.Int("errors", len(result.Errors)))

	return nil
}

// TriggerSyncWithResult triggers a full sync and returns the result
func (a *Application) TriggerSyncWithResult() (*SyncResultData, error) {
	a.logger.Info("Manual sync with result triggered")

	// Get current session for email
	session, err := a.authService.GetCurrentSession(a.ctx)
	if err != nil {
		a.logger.Error("Failed to get session for sync", zap.Error(err))
		return nil, fmt.Errorf("not authenticated: %w", err)
	}

	// Get the stored password for decryption
	var password string
	if a.passwordStore.HasPassword(session.Email) {
		password, err = a.passwordStore.GetPassword(session.Email)
		if err != nil {
			a.logger.Warn("Failed to get stored password, sync will skip decryption", zap.Error(err))
		}
	} else {
		a.logger.Warn("No stored password, sync will skip decryption")
	}

	input := &sync.SyncInput{
		BatchSize:  50,
		MaxBatches: 100,
		Password:   password,
	}

	result, err := a.syncService.SyncAll(a.ctx, input)
	if err != nil {
		a.logger.Error("Sync failed", zap.Error(err))
		return nil, fmt.Errorf("sync failed: %w", err)
	}

	return &SyncResultData{
		CollectionsProcessed: result.CollectionsProcessed,
		CollectionsAdded:     result.CollectionsAdded,
		CollectionsUpdated:   result.CollectionsUpdated,
		CollectionsDeleted:   result.CollectionsDeleted,
		FilesProcessed:       result.FilesProcessed,
		FilesAdded:           result.FilesAdded,
		FilesUpdated:         result.FilesUpdated,
		FilesDeleted:         result.FilesDeleted,
		Errors:               result.Errors,
	}, nil
}

// ResetSync resets all sync state for a fresh sync
func (a *Application) ResetSync() error {
	a.logger.Info("Resetting sync state")
	return a.syncService.ResetSync(a.ctx)
}
