package com.atridad.ascently.data.sync

import android.content.Context
import android.content.SharedPreferences
import androidx.core.content.edit
import com.atridad.ascently.data.repository.ClimbRepository
import com.atridad.ascently.data.state.DataStateManager
import com.atridad.ascently.utils.AppLogger
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock

class SyncService(private val context: Context, private val repository: ClimbRepository) {

    private val serviceScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
    private val syncMutex = Mutex()

    companion object {
        private const val TAG = "SyncService"
    }

    // Currently we only support one provider, but this allows for future expansion
    private val provider: SyncProvider = AscentlySyncProvider(context, repository, DataStateManager(context))

    // State
    private val _isSyncing = MutableStateFlow(false)
    val isSyncing: StateFlow<Boolean> = _isSyncing.asStateFlow()

    private val _lastSyncTime = MutableStateFlow<String?>(null)
    val lastSyncTime: StateFlow<String?> = _lastSyncTime.asStateFlow()

    private val _syncError = MutableStateFlow<String?>(null)
    val syncError: StateFlow<String?> = _syncError.asStateFlow()

    // Delegate to provider
    val isConnected: StateFlow<Boolean> = provider.isConnected
    val isConfiguredFlow: StateFlow<Boolean> = provider.isConfigured

    private val _isTesting = MutableStateFlow(false)
    val isTesting: StateFlow<Boolean> = _isTesting.asStateFlow()

    private val _isAutoSyncEnabled = MutableStateFlow(true)
    val isAutoSyncEnabled: StateFlow<Boolean> = _isAutoSyncEnabled.asStateFlow()

    // Debounced sync properties
    private var syncJob: Job? = null
    private var pendingChanges = false
    private val syncDebounceDelay = 2000L // 2 seconds

    private val sharedPreferences: SharedPreferences =
        context.getSharedPreferences("sync_preferences", Context.MODE_PRIVATE)

    private object Keys {
        const val LAST_SYNC_TIME = "last_sync_time"
        const val AUTO_SYNC_ENABLED = "auto_sync_enabled"
    }

    init {
        loadInitialState()
        repository.setAutoSyncCallback { serviceScope.launch { triggerAutoSync() } }
    }

    private fun loadInitialState() {
        _lastSyncTime.value = sharedPreferences.getString(Keys.LAST_SYNC_TIME, null)
        _isAutoSyncEnabled.value = sharedPreferences.getBoolean(Keys.AUTO_SYNC_ENABLED, true)
    }

    // Proxy properties for Ascently provider configuration
    var serverUrl: String
        get() = (provider as? AscentlySyncProvider)?.serverUrl ?: ""
        set(value) {
            (provider as? AscentlySyncProvider)?.serverUrl = value
        }

    var authToken: String
        get() = (provider as? AscentlySyncProvider)?.authToken ?: ""
        set(value) {
            (provider as? AscentlySyncProvider)?.authToken = value
        }

    fun setAutoSyncEnabled(enabled: Boolean) {
        _isAutoSyncEnabled.value = enabled
        sharedPreferences.edit { putBoolean(Keys.AUTO_SYNC_ENABLED, enabled) }
    }

    suspend fun syncWithServer() {
        if (!isConfiguredFlow.value) {
            throw SyncException.NotConfigured
        }

        syncMutex.withLock {
            _isSyncing.value = true
            _syncError.value = null

            try {
                provider.sync()

                // Update last sync time from shared prefs (provider updates it)
                _lastSyncTime.value = sharedPreferences.getString(Keys.LAST_SYNC_TIME, null)
            } catch (e: Exception) {
                _syncError.value = e.message
                throw e
            } finally {
                _isSyncing.value = false
            }
        }
    }

    suspend fun testConnection() {
        _isTesting.value = true
        _syncError.value = null
        try {
            provider.testConnection()
        } catch (e: Exception) {
            _syncError.value = "Connection error: ${e.message}"
            throw e
        } finally {
            _isTesting.value = false
        }
    }

    fun triggerAutoSync() {
        if (!isConfiguredFlow.value || !isConnected.value || !_isAutoSyncEnabled.value) {
            return
        }
        if (_isSyncing.value) {
            pendingChanges = true
            return
        }
        syncJob?.cancel()
        syncJob =
            serviceScope.launch {
                delay(syncDebounceDelay)
                try {
                    syncWithServer()
                } catch (e: Exception) {
                    AppLogger.e(TAG, e) { "Auto-sync failed" }
                }
                if (pendingChanges) {
                    pendingChanges = false
                    triggerAutoSync()
                }
            }
    }

    fun clearConfiguration() {
        syncJob?.cancel()
        provider.disconnect()
        setAutoSyncEnabled(true)
        _lastSyncTime.value = null
        _syncError.value = null
    }
}
