package com.tt.honeyDue.network

import com.tt.honeyDue.data.DataManager
import com.tt.honeyDue.models.*
import com.tt.honeyDue.network.*
import kotlinx.coroutines.sync.Mutex

/**
 * Unified API Layer that manages all network calls and DataManager updates.
 * This is the single entry point for all data operations in the app.
 *
 * Core Principle: Every API response updates DataManager immediately.
 * All screens observe DataManager StateFlows directly.
 *
 * Data Flow:
 * User Action → API Call → Server Response → DataManager Updated → All Screens React
 */
object APILayer {

    private val residenceApi = ResidenceApi()
    private val taskApi = TaskApi()
    private val taskCompletionApi = TaskCompletionApi()
    private val documentApi = DocumentApi()
    private val contractorApi = ContractorApi()
    private val authApi = AuthApi()
    private val lookupsApi = LookupsApi()
    private val notificationApi = NotificationApi()
    private val subscriptionApi = SubscriptionApi()
    private val taskTemplateApi = TaskTemplateApi()
    private val uploadApi = UploadApi()

    // ==================== Initialization Guards ====================

    /**
     * Thread-safe guard to prevent concurrent initialization calls.
     * Uses Mutex instead of boolean flag for coroutine safety.
     */
    private val lookupsInitMutex = Mutex()

    /**
     * Thread-safe guard to prevent concurrent prefetch calls.
     * Uses Mutex instead of boolean flag for coroutine safety.
     */
    private val prefetchMutex = Mutex()

    // ==================== Authentication Helper ====================

    private fun getToken(): String? = DataManager.authToken.value

    // ==================== Lookups Operations ====================

    /**
     * Refresh subscription status from backend to get updated limits and usage.
     * Call this when app comes to foreground or when limits might have changed.
     */
    suspend fun refreshSubscriptionStatus(): ApiResult<SubscriptionStatus> {
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)

        println("🔄 [APILayer] Force refreshing subscription status from backend...")
        val result = subscriptionApi.getSubscriptionStatus(token)

        when (result) {
            is ApiResult.Success -> {
                println("✅ [APILayer] Subscription status refreshed successfully")
                println("   📊 Limitations Enabled: ${result.data.limitationsEnabled}")
                DataManager.setSubscription(result.data)
            }
            is ApiResult.Error -> {
                println("❌ [APILayer] Failed to refresh subscription status: ${result.message}")
            }
            else -> {}
        }

        return result
    }

    /**
     * Initialize all lookup data. Can be called at app start even without authentication.
     * Loads all reference data (residence types, task categories, priorities, etc.) into DataManager.
     *
     * Uses ETag-based conditional fetching - if data hasn't changed on server, returns 304 Not Modified
     * and uses existing cached data. This is efficient for app foreground/resume scenarios.
     *
     * - /static_data/ and /upgrade-triggers/ are public endpoints (no auth required)
     * - /subscription/status/ requires auth and is only called if user is authenticated
     */
    suspend fun initializeLookups(): ApiResult<Unit> {
        // Guard: prevent concurrent initialization (thread-safe via Mutex)
        if (!lookupsInitMutex.tryLock()) {
            println("📋 [APILayer] Lookups initialization already in progress, skipping...")
            return ApiResult.Success(Unit)
        }

        val token = getToken()
        val currentETag = DataManager.seededDataETag.value

        // If lookups are already initialized and we have an ETag, do conditional fetch
        if (DataManager.lookupsInitialized.value && currentETag != null) {
            lookupsInitMutex.unlock()
            println("📋 [APILayer] Lookups initialized, checking for updates with ETag...")
            return refreshLookupsIfChanged()
        }

        try {
            // Use seeded data endpoint with ETag support (PUBLIC - no auth required)
            // Only send ETag if lookups are already in memory - otherwise we need full data
            // (ETag may be persisted from previous session but lookup data wasn't loaded)
            val hasLookupsInMemory = DataManager.residenceTypes.value.isNotEmpty()
            val etagToSend = if (hasLookupsInMemory) currentETag else null
            println("🔄 Fetching seeded data (all lookups + templates)... ETag: $etagToSend (has data in memory: $hasLookupsInMemory)")
            val seededDataResult = lookupsApi.getSeededData(etagToSend, token)
            println("📦 Seeded data result: $seededDataResult")

            when (seededDataResult) {
                is ConditionalResult.Success -> {
                    println("✅ Seeded data loaded successfully")
                    DataManager.setAllLookupsFromSeededData(seededDataResult.data, seededDataResult.etag)
                }
                is ConditionalResult.NotModified -> {
                    println("✅ Seeded data not modified, using cached data")
                    DataManager.markLookupsInitialized()
                }
                is ConditionalResult.Error -> {
                    println("❌ Failed to fetch seeded data: ${seededDataResult.message}")
                    // Fallback to old static_data endpoint without task templates
                    return fallbackToLegacyStaticData(token)
                }
            }

            // Load upgrade triggers (PUBLIC - no auth required)
            println("🔄 Fetching upgrade triggers...")
            val upgradeTriggersResult = subscriptionApi.getUpgradeTriggers(token)
            println("📦 Upgrade triggers result: $upgradeTriggersResult")

            if (upgradeTriggersResult is ApiResult.Success) {
                println("✅ Updating upgrade triggers with ${upgradeTriggersResult.data.size} triggers")
                DataManager.setUpgradeTriggers(upgradeTriggersResult.data)
                println("✅ Upgrade triggers updated successfully")
            } else if (upgradeTriggersResult is ApiResult.Error) {
                println("❌ Failed to fetch upgrade triggers: ${upgradeTriggersResult.message}")
            }

            // Load subscription status only if authenticated (requires auth for user-specific data)
            if (token != null) {
                println("🔄 Fetching subscription status...")
                val subscriptionStatusResult = subscriptionApi.getSubscriptionStatus(token)
                println("📦 Subscription status result: $subscriptionStatusResult")

                if (subscriptionStatusResult is ApiResult.Success) {
                    println("✅ Updating DataManager with subscription: ${subscriptionStatusResult.data}")
                    DataManager.setSubscription(subscriptionStatusResult.data)
                    println("✅ Subscription updated successfully")
                } else if (subscriptionStatusResult is ApiResult.Error) {
                    println("❌ Failed to fetch subscription status: ${subscriptionStatusResult.message}")
                }

                // Load feature benefits (auth required)
                println("🔄 Fetching feature benefits...")
                val featureBenefitsResult = subscriptionApi.getFeatureBenefits(token)
                if (featureBenefitsResult is ApiResult.Success) {
                    println("✅ Feature benefits loaded: ${featureBenefitsResult.data.size} features")
                    DataManager.setFeatureBenefits(featureBenefitsResult.data)
                } else if (featureBenefitsResult is ApiResult.Error) {
                    println("❌ Failed to fetch feature benefits: ${featureBenefitsResult.message}")
                }

                // Load contractors if cache is empty or stale
                if (!DataManager.isCacheValid(DataManager.contractorsCacheTime)) {
                    println("🔄 Fetching contractors...")
                    val contractorsResult = contractorApi.getContractors(token, null, null, null, null)
                    if (contractorsResult is ApiResult.Success) {
                        println("✅ Contractors loaded: ${contractorsResult.data.size} contractors")
                        DataManager.setContractors(contractorsResult.data)
                    } else if (contractorsResult is ApiResult.Error) {
                        println("❌ Failed to fetch contractors: ${contractorsResult.message}")
                    }
                } else {
                    println("⏭️ Skipping contractors (cache still valid)")
                }
            } else {
                println("⏭️ Skipping subscription status and contractors (not authenticated)")
            }

            DataManager.markLookupsInitialized()
            return ApiResult.Success(Unit)
        } catch (e: Exception) {
            return ApiResult.Error("Failed to initialize lookups: ${e.message}")
        } finally {
            lookupsInitMutex.unlock()
        }
    }

    /**
     * Refresh lookups only if data has changed on server (using ETag).
     * Called when app comes to foreground or resumes.
     * Returns quickly with 304 Not Modified if data hasn't changed.
     */
    suspend fun refreshLookupsIfChanged(): ApiResult<Unit> {
        val token = getToken()
        val currentETag = DataManager.seededDataETag.value

        // Only send ETag if we actually have lookup data in memory
        // Otherwise we need a full fetch to populate the cache
        val hasLookupsInMemory = DataManager.residenceTypes.value.isNotEmpty()
        val etagToSend = if (hasLookupsInMemory) currentETag else null

        println("🔄 [APILayer] Checking if lookups have changed (ETag: $etagToSend, has data: $hasLookupsInMemory)...")

        val seededDataResult = lookupsApi.getSeededData(etagToSend, token)

        when (seededDataResult) {
            is ConditionalResult.Success -> {
                println("✅ Lookups have changed, updating DataManager")
                DataManager.setAllLookupsFromSeededData(seededDataResult.data, seededDataResult.etag)
            }
            is ConditionalResult.NotModified -> {
                println("✅ Lookups unchanged (304 Not Modified)")
            }
            is ConditionalResult.Error -> {
                println("❌ Failed to check lookup updates: ${seededDataResult.message}")
                // Non-fatal - continue using cached data
            }
        }

        // Refresh subscription status if authenticated
        if (token != null) {
            refreshSubscriptionStatus()
        }

        return ApiResult.Success(Unit)
    }

    /**
     * Fallback to legacy static_data endpoint if seeded_data fails.
     * Does not include task templates.
     */
    private suspend fun fallbackToLegacyStaticData(token: String?): ApiResult<Unit> {
        println("🔄 Falling back to legacy static data endpoint...")
        val staticDataResult = lookupsApi.getStaticData(token)

        if (staticDataResult is ApiResult.Success) {
            DataManager.setAllLookups(staticDataResult.data)
            println("✅ Legacy static data loaded successfully")

            // Try to load task templates separately
            val templatesResult = taskTemplateApi.getTemplatesGrouped()
            if (templatesResult is ApiResult.Success) {
                DataManager.setTaskTemplatesGrouped(templatesResult.data)
            }

            DataManager.markLookupsInitialized()
            return ApiResult.Success(Unit)
        } else if (staticDataResult is ApiResult.Error) {
            return ApiResult.Error("Failed to load lookups: ${staticDataResult.message}")
        }

        return ApiResult.Error("Unknown error loading lookups")
    }

    /**
     * Get residence types from DataManager. If cache is empty, fetch from API.
     */
    suspend fun getResidenceTypes(forceRefresh: Boolean = false): ApiResult<List<ResidenceType>> {
        if (!forceRefresh) {
            val cached = DataManager.residenceTypes.value
            if (cached.isNotEmpty()) {
                return ApiResult.Success(cached)
            }
        }

        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        val result = lookupsApi.getResidenceTypes(token)

        if (result is ApiResult.Success) {
            DataManager.setResidenceTypes(result.data)
        }

        return result
    }

    /**
     * Get task frequencies from DataManager. If cache is empty, fetch from API.
     */
    suspend fun getTaskFrequencies(forceRefresh: Boolean = false): ApiResult<List<TaskFrequency>> {
        if (!forceRefresh) {
            val cached = DataManager.taskFrequencies.value
            if (cached.isNotEmpty()) {
                return ApiResult.Success(cached)
            }
        }

        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        val result = lookupsApi.getTaskFrequencies(token)

        if (result is ApiResult.Success) {
            DataManager.setTaskFrequencies(result.data)
        }

        return result
    }

    /**
     * Get task priorities from DataManager. If cache is empty, fetch from API.
     */
    suspend fun getTaskPriorities(forceRefresh: Boolean = false): ApiResult<List<TaskPriority>> {
        if (!forceRefresh) {
            val cached = DataManager.taskPriorities.value
            if (cached.isNotEmpty()) {
                return ApiResult.Success(cached)
            }
        }

        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        val result = lookupsApi.getTaskPriorities(token)

        if (result is ApiResult.Success) {
            DataManager.setTaskPriorities(result.data)
        }

        return result
    }

    /**
     * Get task categories from DataManager. If cache is empty, fetch from API.
     */
    suspend fun getTaskCategories(forceRefresh: Boolean = false): ApiResult<List<TaskCategory>> {
        if (!forceRefresh) {
            val cached = DataManager.taskCategories.value
            if (cached.isNotEmpty()) {
                return ApiResult.Success(cached)
            }
        }

        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        val result = lookupsApi.getTaskCategories(token)

        if (result is ApiResult.Success) {
            DataManager.setTaskCategories(result.data)
        }

        return result
    }

    /**
     * Get contractor specialties from DataManager. If cache is empty, fetch from API.
     */
    suspend fun getContractorSpecialties(forceRefresh: Boolean = false): ApiResult<List<ContractorSpecialty>> {
        if (!forceRefresh) {
            val cached = DataManager.contractorSpecialties.value
            if (cached.isNotEmpty()) {
                return ApiResult.Success(cached)
            }
        }

        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        val result = lookupsApi.getContractorSpecialties(token)

        if (result is ApiResult.Success) {
            DataManager.setContractorSpecialties(result.data)
        }

        return result
    }

    // ==================== Residence Operations ====================

    suspend fun getResidences(forceRefresh: Boolean = false): ApiResult<List<ResidenceResponse>> {
        // Check DataManager first - return cached if valid and not forcing refresh
        // Cache is valid even if empty (user has no residences)
        if (!forceRefresh && DataManager.isCacheValid(DataManager.residencesCacheTime)) {
            println("[APILayer] CACHE HIT: residences")
            return ApiResult.Success(DataManager.residences.value)
        }
        println("[APILayer] CACHE MISS: residences (forceRefresh=$forceRefresh)")

        // Fetch from API
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        val result = residenceApi.getResidences(token)

        // Update DataManager on success
        if (result is ApiResult.Success) {
            DataManager.setResidences(result.data)
        }

        return result
    }

    suspend fun getMyResidences(forceRefresh: Boolean = false): ApiResult<MyResidencesResponse> {
        // Check DataManager first - return cached if valid and not forcing refresh
        if (!forceRefresh && DataManager.isCacheValid(DataManager.myResidencesCacheTime)) {
            val cached = DataManager.myResidences.value
            if (cached != null) {
                println("[APILayer] CACHE HIT: myResidences")
                return ApiResult.Success(cached)
            }
        }
        println("[APILayer] CACHE MISS: myResidences (forceRefresh=$forceRefresh)")

        // Fetch from API
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        val result = residenceApi.getMyResidences(token)

        // Update DataManager on success
        if (result is ApiResult.Success) {
            val oldCount = DataManager.myResidences.value?.residences?.size ?: 0
            DataManager.setMyResidences(result.data)
            val newCount = result.data.residences.size
            // Residence list changed (join/leave/create/delete) — invalidate task cache
            // so next loadTasks() fetches fresh data including tasks from new residences
            if (newCount != oldCount) {
                println("[APILayer] Residence count changed ($oldCount → $newCount), invalidating tasks cache")
                DataManager.invalidateTasksCache()
            }
        }

        return result
    }

    /**
     * Accept a residence invite (push-notification action button).
     * Refreshes myResidences on success so the new residence appears in the
     * cache without requiring a manual pull-to-refresh.
     */
    suspend fun acceptResidenceInvite(residenceId: Int): ApiResult<Unit> {
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        val result = residenceApi.acceptResidenceInvite(token, residenceId)
        if (result is ApiResult.Success) {
            // Residence list may have changed — force a refresh so any
            // newly-joined residence shows up in the home screen.
            getMyResidences(forceRefresh = true)
        }
        return result
    }

    /**
     * Decline a residence invite (push-notification action button).
     * Does not require cache refresh — pending-invites are not cached
     * client-side; the next app-open will re-query the server anyway.
     */
    suspend fun declineResidenceInvite(residenceId: Int): ApiResult<Unit> {
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        return residenceApi.declineResidenceInvite(token, residenceId)
    }

    suspend fun getResidence(id: Int, forceRefresh: Boolean = false): ApiResult<ResidenceResponse> {
        // Check DataManager caches first - return cached if valid and not forcing refresh
        if (!forceRefresh) {
            // Check residences list
            if (DataManager.isCacheValid(DataManager.residencesCacheTime)) {
                val cached = DataManager.residences.value.find { it.id == id }
                if (cached != null) {
                    return ApiResult.Success(cached)
                }
            }
            // Also check myResidences (loaded from home screen)
            if (DataManager.isCacheValid(DataManager.myResidencesCacheTime)) {
                val cached = DataManager.myResidences.value?.residences?.find { it.id == id }
                if (cached != null) {
                    return ApiResult.Success(cached)
                }
            }
        }

        // Fetch from API
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        val result = residenceApi.getResidence(token, id)

        // Update DataManager on success
        if (result is ApiResult.Success) {
            DataManager.updateResidence(result.data)
        }

        return result
    }

    /**
     * Get total summary (task counts across all residences).
     * This is a lightweight endpoint for refreshing summary counts.
     */
    suspend fun getSummary(forceRefresh: Boolean = false): ApiResult<TotalSummary> {
        // Check DataManager first - return cached if valid and not forcing refresh
        if (!forceRefresh && DataManager.isCacheValid(DataManager.summaryCacheTime)) {
            val cached = DataManager.totalSummary.value
            if (cached != null) {
                return ApiResult.Success(cached)
            }
        }

        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        val result = residenceApi.getSummary(token)

        if (result is ApiResult.Success) {
            DataManager.setTotalSummary(result.data)
        }

        return result
    }

    suspend fun createResidence(request: ResidenceCreateRequest): ApiResult<ResidenceResponse> {
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        val result = residenceApi.createResidence(token, request)

        // Extract summary and update local cache
        if (result is ApiResult.Success) {
            DataManager.setTotalSummary(result.data.summary)
            DataManager.addResidence(result.data.data)
            return ApiResult.Success(result.data.data)
        }

        return when (result) {
            is ApiResult.Error -> result
            else -> ApiResult.Error("Unknown error")
        }
    }

    suspend fun updateResidence(id: Int, request: ResidenceCreateRequest): ApiResult<ResidenceResponse> {
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        val result = residenceApi.updateResidence(token, id, request)

        // Extract summary and update local cache
        if (result is ApiResult.Success) {
            DataManager.setTotalSummary(result.data.summary)
            DataManager.updateResidence(result.data.data)
            return ApiResult.Success(result.data.data)
        }

        return when (result) {
            is ApiResult.Error -> result
            else -> ApiResult.Error("Unknown error")
        }
    }

    suspend fun deleteResidence(id: Int): ApiResult<Unit> {
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        val result = residenceApi.deleteResidence(token, id)

        // Extract summary and update local cache
        if (result is ApiResult.Success) {
            DataManager.setTotalSummary(result.data.summary)
            DataManager.removeResidence(id)
            return ApiResult.Success(Unit)
        }

        return when (result) {
            is ApiResult.Error -> result
            else -> ApiResult.Error("Unknown error")
        }
    }

    suspend fun generateTasksReport(residenceId: Int, email: String? = null): ApiResult<GenerateReportResponse> {
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        return residenceApi.generateTasksReport(token, residenceId, email)
    }

    suspend fun joinWithCode(code: String): ApiResult<JoinResidenceResponse> {
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        val result = residenceApi.joinWithCode(token, code)

        // Extract summary and update local cache
        if (result is ApiResult.Success) {
            DataManager.setTotalSummary(result.data.summary)
            DataManager.addResidence(result.data.residence)
        }

        return result
    }

    suspend fun getResidenceUsers(residenceId: Int): ApiResult<ResidenceUsersResponse> {
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        return residenceApi.getResidenceUsers(token, residenceId)
    }

    suspend fun getShareCode(residenceId: Int): ApiResult<ShareCodeResponse> {
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        return residenceApi.getShareCode(token, residenceId)
    }

    suspend fun generateShareCode(residenceId: Int): ApiResult<GenerateShareCodeResponse> {
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        return residenceApi.generateShareCode(token, residenceId)
    }

    suspend fun generateSharePackage(residenceId: Int): ApiResult<SharedResidence> {
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        return residenceApi.generateSharePackage(token, residenceId)
    }

    suspend fun removeUser(residenceId: Int, userId: Int): ApiResult<RemoveUserResponse> {
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        return residenceApi.removeUser(token, residenceId, userId)
    }

    // ==================== Task Operations ====================

    suspend fun getTasks(forceRefresh: Boolean = false): ApiResult<TaskColumnsResponse> {
        // Check DataManager first - return cached if valid and not forcing refresh
        if (!forceRefresh && DataManager.isCacheValid(DataManager.tasksCacheTime)) {
            val cached = DataManager.allTasks.value
            if (cached != null) {
                println("[APILayer] CACHE HIT: tasks")
                return ApiResult.Success(cached)
            }
        }
        println("[APILayer] CACHE MISS: tasks (forceRefresh=$forceRefresh)")

        // Fetch from API
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        val result = taskApi.getTasks(token)

        // Update DataManager on success
        if (result is ApiResult.Success) {
            DataManager.setAllTasks(result.data)
        }

        return result
    }

    suspend fun getTasksByResidence(residenceId: Int, forceRefresh: Boolean = false): ApiResult<TaskColumnsResponse> {
        // 1. Check residence-specific cache first
        if (!forceRefresh && DataManager.isCacheValid(DataManager.tasksByResidenceCacheTime[residenceId] ?: 0L)) {
            val cached = DataManager.tasksByResidence.value[residenceId]
            if (cached != null) {
                return ApiResult.Success(cached)
            }
        }

        // 2. Try filtering from allTasks cache before hitting API (optimization)
        // This avoids a redundant API call when we already have all tasks loaded
        if (!forceRefresh && DataManager.isCacheValid(DataManager.tasksCacheTime)) {
            val filtered = DataManager.getTasksForResidence(residenceId)
            if (filtered != null) {
                // Cache the filtered result for future use
                DataManager.setTasksForResidence(residenceId, filtered)
                return ApiResult.Success(filtered)
            }
        }

        // 3. Fallback: Fetch from API
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        val result = taskApi.getTasksByResidence(token, residenceId)

        // Update DataManager on success
        if (result is ApiResult.Success) {
            DataManager.setTasksForResidence(residenceId, result.data)
        }

        return result
    }

    suspend fun createTask(request: TaskCreateRequest): ApiResult<TaskResponse> {
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        val result = taskApi.createTask(token, request)

        // Extract summary and update local cache with new task
        if (result is ApiResult.Success) {
            DataManager.setTotalSummary(result.data.summary)
            // Add the new task to the appropriate kanban column (uses kanbanColumn from response)
            DataManager.updateTask(result.data.data)
            return ApiResult.Success(result.data.data)
        }

        return when (result) {
            is ApiResult.Error -> result
            else -> ApiResult.Error("Unknown error")
        }
    }

    /**
     * Atomically creates 1-50 tasks via POST /api/tasks/bulk/. The whole
     * batch succeeds or fails together on the server. On success, every
     * returned task is merged into DataManager.allTasks so observing views
     * render the new batch immediately.
     */
    suspend fun bulkCreateTasks(request: BulkCreateTasksRequest): ApiResult<BulkCreateTasksResponse> {
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        val result = taskApi.bulkCreateTasks(token, request)

        if (result is ApiResult.Success) {
            DataManager.setTotalSummary(result.data.summary)
            result.data.tasks.forEach { DataManager.updateTask(it) }
        }
        return result
    }

    suspend fun updateTask(id: Int, request: TaskCreateRequest): ApiResult<TaskResponse> {
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        val result = taskApi.updateTask(token, id, request)

        // Extract summary and update local cache with modified task
        if (result is ApiResult.Success) {
            DataManager.setTotalSummary(result.data.summary)
            // Update task in cache (handles column changes if due date changed)
            DataManager.updateTask(result.data.data)
            return ApiResult.Success(result.data.data)
        }

        return when (result) {
            is ApiResult.Error -> result
            else -> ApiResult.Error("Unknown error")
        }
    }

    suspend fun cancelTask(taskId: Int): ApiResult<TaskResponse> {
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        val result = taskApi.cancelTask(token, taskId)

        if (result is ApiResult.Success) {
            DataManager.setTotalSummary(result.data.summary)
            DataManager.updateTask(result.data.data)
            return ApiResult.Success(result.data.data)
        }

        return when (result) {
            is ApiResult.Error -> result
            else -> ApiResult.Error("Unknown error")
        }
    }

    suspend fun uncancelTask(taskId: Int): ApiResult<TaskResponse> {
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        val result = taskApi.uncancelTask(token, taskId)

        if (result is ApiResult.Success) {
            DataManager.setTotalSummary(result.data.summary)
            DataManager.updateTask(result.data.data)
            return ApiResult.Success(result.data.data)
        }

        return when (result) {
            is ApiResult.Error -> result
            else -> ApiResult.Error("Unknown error")
        }
    }

    suspend fun markInProgress(taskId: Int): ApiResult<TaskResponse> {
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        val result = taskApi.markInProgress(token, taskId)

        if (result is ApiResult.Success) {
            DataManager.setTotalSummary(result.data.summary)
            DataManager.updateTask(result.data.data)
            return ApiResult.Success(result.data.data)
        }

        return when (result) {
            is ApiResult.Error -> result
            else -> ApiResult.Error("Unknown error")
        }
    }

    suspend fun clearInProgress(taskId: Int): ApiResult<TaskResponse> {
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        val result = taskApi.clearInProgress(token, taskId)

        if (result is ApiResult.Success) {
            DataManager.setTotalSummary(result.data.summary)
            DataManager.updateTask(result.data.data)
            return ApiResult.Success(result.data.data)
        }

        return when (result) {
            is ApiResult.Error -> result
            else -> ApiResult.Error("Unknown error")
        }
    }

    suspend fun archiveTask(taskId: Int): ApiResult<TaskResponse> {
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        val result = taskApi.archiveTask(token, taskId)

        if (result is ApiResult.Success) {
            DataManager.setTotalSummary(result.data.summary)
            DataManager.removeTask(taskId)
            return ApiResult.Success(result.data.data)
        }

        return when (result) {
            is ApiResult.Error -> result
            else -> ApiResult.Error("Unknown error")
        }
    }

    suspend fun unarchiveTask(taskId: Int): ApiResult<TaskResponse> {
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        val result = taskApi.unarchiveTask(token, taskId)

        if (result is ApiResult.Success) {
            DataManager.setTotalSummary(result.data.summary)
            DataManager.updateTask(result.data.data)
            return ApiResult.Success(result.data.data)
        }

        return when (result) {
            is ApiResult.Error -> result
            else -> ApiResult.Error("Unknown error")
        }
    }

    suspend fun createTaskCompletion(request: TaskCompletionCreateRequest): ApiResult<TaskCompletionResponse> {
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        val result = taskCompletionApi.createCompletion(token, request)

        if (result is ApiResult.Success) {
            // Update summary from response - eliminates need for separate getSummary call
            DataManager.setTotalSummary(result.data.summary)
            // The response includes the updated task, update it in DataManager
            result.data.data.updatedTask?.let { updatedTask ->
                DataManager.updateTask(updatedTask)
            }
            return ApiResult.Success(result.data.data)
        }

        return when (result) {
            is ApiResult.Error -> result
            else -> ApiResult.Error("Unknown error")
        }
    }

    /**
     * Get all completions for a specific task
     */
    suspend fun getTaskCompletions(taskId: Int): ApiResult<List<TaskCompletionResponse>> {
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        val result = taskApi.getTaskCompletions(token, taskId)
        if (result is ApiResult.Success) {
            DataManager.setTaskCompletions(taskId, result.data)
        }
        return result
    }

    // ==================== Document Operations ====================

    suspend fun getDocuments(
        residenceId: Int? = null,
        documentType: String? = null,
        category: String? = null,
        contractorId: Int? = null,
        isActive: Boolean? = null,
        expiringSoon: Int? = null,
        tags: String? = null,
        search: String? = null,
        forceRefresh: Boolean = false
    ): ApiResult<List<Document>> {
        val hasFilters = residenceId != null || documentType != null || category != null ||
                        contractorId != null || isActive != null || expiringSoon != null ||
                        tags != null || search != null

        // Check DataManager first if no filters - return cached if valid and not forcing refresh
        // Cache is valid even if empty (user has no documents)
        if (!forceRefresh && !hasFilters && DataManager.isCacheValid(DataManager.documentsCacheTime)) {
            println("[APILayer] CACHE HIT: documents")
            return ApiResult.Success(DataManager.documents.value)
        }
        println("[APILayer] CACHE MISS: documents (forceRefresh=$forceRefresh, hasFilters=$hasFilters)")

        // Fetch from API
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        val result = documentApi.getDocuments(
            token, residenceId, documentType, category, contractorId,
            isActive, expiringSoon, tags, search
        )

        // Update DataManager on success if no filters
        if (result is ApiResult.Success && !hasFilters) {
            DataManager.setDocuments(result.data)
        }

        return result
    }

    suspend fun getDocument(id: Int, forceRefresh: Boolean = false): ApiResult<Document> {
        // Check DataManager first - return cached if valid and not forcing refresh
        if (!forceRefresh && DataManager.isCacheValid(DataManager.documentsCacheTime)) {
            val cached = DataManager.documents.value.find { it.id == id }
            if (cached != null) {
                return ApiResult.Success(cached)
            }
        }

        // Fetch from API
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        val result = documentApi.getDocument(token, id)

        // Update DataManager on success
        if (result is ApiResult.Success) {
            DataManager.updateDocument(result.data)
            DataManager.setDocumentDetail(result.data)
        }

        return result
    }

    suspend fun createDocument(
        title: String,
        documentType: String,
        residenceId: Int,
        description: String? = null,
        category: String? = null,
        tags: String? = null,
        notes: String? = null,
        contractorId: Int? = null,
        isActive: Boolean = true,
        itemName: String? = null,
        modelNumber: String? = null,
        serialNumber: String? = null,
        provider: String? = null,
        providerContact: String? = null,
        claimPhone: String? = null,
        claimEmail: String? = null,
        claimWebsite: String? = null,
        purchaseDate: String? = null,
        startDate: String? = null,
        endDate: String? = null,
        fileBytes: ByteArray? = null,
        fileName: String? = null,
        mimeType: String? = null,
        fileBytesList: List<ByteArray>? = null,
        fileNamesList: List<String>? = null,
        mimeTypesList: List<String>? = null
    ): ApiResult<Document> {
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        val result = documentApi.createDocument(
            token, title, documentType, residenceId, description, category,
            tags, notes, contractorId, isActive, itemName, modelNumber,
            serialNumber, provider, providerContact, claimPhone, claimEmail,
            claimWebsite, purchaseDate, startDate, endDate, fileBytes, fileName,
            mimeType, fileBytesList, fileNamesList, mimeTypesList
        )

        // Update DataManager on success
        if (result is ApiResult.Success) {
            DataManager.addDocument(result.data)
        }

        return result
    }

    suspend fun updateDocument(
        id: Int,
        title: String,
        documentType: String,
        description: String? = null,
        category: String? = null,
        tags: String? = null,
        notes: String? = null,
        contractorId: Int? = null,
        isActive: Boolean = true,
        itemName: String? = null,
        modelNumber: String? = null,
        serialNumber: String? = null,
        provider: String? = null,
        providerContact: String? = null,
        claimPhone: String? = null,
        claimEmail: String? = null,
        claimWebsite: String? = null,
        purchaseDate: String? = null,
        startDate: String? = null,
        endDate: String? = null
    ): ApiResult<Document> {
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        val result = documentApi.updateDocument(
            token, id, title, documentType, description, category, tags, notes,
            contractorId, isActive, itemName, modelNumber, serialNumber, provider,
            providerContact, claimPhone, claimEmail, claimWebsite, purchaseDate,
            startDate, endDate
        )

        // Update DataManager on success
        if (result is ApiResult.Success) {
            DataManager.updateDocument(result.data)
        }

        return result
    }

    suspend fun deleteDocument(id: Int): ApiResult<Unit> {
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        val result = documentApi.deleteDocument(token, id)

        // Update DataManager on success
        if (result is ApiResult.Success) {
            DataManager.removeDocument(id)
        }

        return result
    }

    suspend fun uploadDocumentImage(
        documentId: Int,
        imageBytes: ByteArray,
        fileName: String,
        mimeType: String,
        caption: String? = null
    ): ApiResult<Document> {
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        val result = documentApi.uploadDocumentImage(token, documentId, imageBytes, fileName, mimeType, caption)
        if (result is ApiResult.Success) {
            DataManager.updateDocument(result.data)
        }
        return result
    }

    suspend fun deleteDocumentImage(documentId: Int, imageId: Int): ApiResult<Document> {
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        val result = documentApi.deleteDocumentImage(token, documentId, imageId)
        if (result is ApiResult.Success) {
            DataManager.updateDocument(result.data)
        }
        return result
    }

    suspend fun downloadDocument(url: String): ApiResult<ByteArray> {
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        return documentApi.downloadDocument(token, url)
    }

    // ==================== Contractor Operations ====================

    suspend fun getContractors(
        specialty: String? = null,
        isFavorite: Boolean? = null,
        isActive: Boolean? = null,
        search: String? = null,
        forceRefresh: Boolean = false
    ): ApiResult<List<ContractorSummary>> {
        val hasFilters = specialty != null || isFavorite != null || isActive != null || search != null

        // Check cache first (only if no filters applied) - return cached if valid and not forcing refresh
        // Cache is valid even if empty (user has no contractors)
        if (!forceRefresh && !hasFilters && DataManager.isCacheValid(DataManager.contractorsCacheTime)) {
            return ApiResult.Success(DataManager.contractors.value)
        }

        // Fetch from API
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        val result = contractorApi.getContractors(token, specialty, isFavorite, isActive, search)

        // Update DataManager on success (only for unfiltered results)
        if (result is ApiResult.Success && !hasFilters) {
            DataManager.setContractors(result.data)
        }

        return result
    }

    suspend fun getContractor(id: Int, forceRefresh: Boolean = false): ApiResult<Contractor> {
        // Fetch from API (summaries don't have full detail, always fetch)
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        val result = contractorApi.getContractor(token, id)

        // Update the summary in DataManager on success
        if (result is ApiResult.Success) {
            DataManager.updateContractor(result.data)
            DataManager.setContractorDetail(result.data)
        }

        return result
    }

    suspend fun createContractor(request: ContractorCreateRequest): ApiResult<Contractor> {
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        val result = contractorApi.createContractor(token, request)

        // Update DataManager on success
        if (result is ApiResult.Success) {
            DataManager.addContractor(result.data)
        }

        return result
    }

    suspend fun updateContractor(id: Int, request: ContractorUpdateRequest): ApiResult<Contractor> {
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        val result = contractorApi.updateContractor(token, id, request)

        // Update DataManager on success
        if (result is ApiResult.Success) {
            DataManager.updateContractor(result.data)
        }

        return result
    }

    suspend fun deleteContractor(id: Int): ApiResult<Unit> {
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        val result = contractorApi.deleteContractor(token, id)

        // Update DataManager on success
        if (result is ApiResult.Success) {
            DataManager.removeContractor(id)
        }

        return result
    }

    suspend fun toggleFavorite(id: Int): ApiResult<Contractor> {
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        val result = contractorApi.toggleFavorite(token, id)

        // Update DataManager on success
        if (result is ApiResult.Success) {
            DataManager.updateContractor(result.data)
        }

        return result
    }

    suspend fun getContractorsByResidence(residenceId: Int, forceRefresh: Boolean = false): ApiResult<List<ContractorSummary>> {
        // Check cache first - filter contractors by residenceId
        if (!forceRefresh && DataManager.isCacheValid(DataManager.contractorsCacheTime)) {
            val cachedContractors = DataManager.contractors.value
            val filtered = cachedContractors.filter { it.residenceId == residenceId }
            DataManager.setContractorsForResidence(residenceId, filtered)
            return ApiResult.Success(filtered)
        }

        // If cache is empty or stale, fetch all contractors first to populate cache
        if (DataManager.contractors.value.isEmpty() || !DataManager.isCacheValid(DataManager.contractorsCacheTime)) {
            val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
            val result = contractorApi.getContractors(token, null, null, null, null)
            if (result is ApiResult.Success) {
                DataManager.setContractors(result.data)
                // Now filter from the fresh cache
                val filtered = result.data.filter { it.residenceId == residenceId }
                DataManager.setContractorsForResidence(residenceId, filtered)
                return ApiResult.Success(filtered)
            }
            return result as ApiResult<List<ContractorSummary>>
        }

        // Fallback: filter from cache
        val filtered = DataManager.contractors.value.filter { it.residenceId == residenceId }
        DataManager.setContractorsForResidence(residenceId, filtered)
        return ApiResult.Success(filtered)
    }

    // ==================== Task Template Operations ====================
    // Task templates are now included in seeded data, so these methods primarily use cache.
    // If forceRefresh is needed, use refreshLookupsIfChanged() to get fresh data from server.

    /**
     * Get all task templates from DataManager.
     * Templates are loaded with seeded data, so this uses cache.
     * Use forceRefresh to trigger a full seeded data refresh.
     */
    suspend fun getTaskTemplates(forceRefresh: Boolean = false): ApiResult<List<TaskTemplate>> {
        if (forceRefresh) {
            // Force refresh via seeded data endpoint (includes templates)
            refreshLookupsIfChanged()
        }

        val cached = DataManager.taskTemplates.value
        if (cached.isNotEmpty()) {
            return ApiResult.Success(cached)
        }

        // If still empty, initialize lookups (which includes templates via seeded data)
        initializeLookups()
        return ApiResult.Success(DataManager.taskTemplates.value)
    }

    /**
     * Get task templates grouped by category.
     * Templates are loaded with seeded data, so this uses cache.
     */
    suspend fun getTaskTemplatesGrouped(forceRefresh: Boolean = false): ApiResult<TaskTemplatesGroupedResponse> {
        if (forceRefresh) {
            // Force refresh via seeded data endpoint (includes templates)
            refreshLookupsIfChanged()
        }

        val cached = DataManager.taskTemplatesGrouped.value
        if (cached != null) {
            return ApiResult.Success(cached)
        }

        // If still empty, initialize lookups (which includes templates via seeded data)
        initializeLookups()
        return DataManager.taskTemplatesGrouped.value?.let {
            ApiResult.Success(it)
        } ?: ApiResult.Error("Failed to load task templates")
    }

    /**
     * Search task templates by query string.
     * Uses local cache only - templates are loaded with seeded data.
     */
    suspend fun searchTaskTemplates(query: String): ApiResult<List<TaskTemplate>> {
        // Ensure templates are loaded
        if (DataManager.taskTemplates.value.isEmpty()) {
            initializeLookups()
        }

        val results = DataManager.searchTaskTemplates(query)
        return ApiResult.Success(results)
    }

    /**
     * Get templates by category ID.
     * Uses local cache only - templates are loaded with seeded data.
     */
    suspend fun getTemplatesByCategory(categoryId: Int): ApiResult<List<TaskTemplate>> {
        // Ensure templates are loaded
        if (DataManager.taskTemplatesGrouped.value == null) {
            initializeLookups()
        }

        val grouped = DataManager.taskTemplatesGrouped.value
        val categoryTemplates = grouped?.categories
            ?.find { it.categoryId == categoryId }?.templates
            ?: emptyList()

        return ApiResult.Success(categoryTemplates)
    }

    /**
     * Get a single task template by ID.
     * Uses local cache only - templates are loaded with seeded data.
     */
    suspend fun getTaskTemplate(id: Int): ApiResult<TaskTemplate> {
        // Ensure templates are loaded
        if (DataManager.taskTemplates.value.isEmpty()) {
            initializeLookups()
        }

        val cached = DataManager.taskTemplates.value.find { it.id == id }
        return cached?.let {
            ApiResult.Success(it)
        } ?: ApiResult.Error("Task template not found")
    }

    /**
     * Get personalized task suggestions for a residence based on its home profile.
     */
    suspend fun getTaskSuggestions(residenceId: Int): ApiResult<TaskSuggestionsResponse> {
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        return taskTemplateApi.getTaskSuggestions(token, residenceId)
    }

    // ==================== Auth Operations ====================

    suspend fun login(request: LoginRequest): ApiResult<AuthResponse> {
        val result = authApi.login(request)

        // Update DataManager on success
        if (result is ApiResult.Success) {
            DataManager.setAuthToken(result.data.token)
            DataManager.setCurrentUser(result.data.user)
            // Initialize lookups after successful login
            initializeLookups()
            // Prefetch all data
            prefetchAllData()
        }

        return result
    }

    suspend fun register(request: RegisterRequest): ApiResult<AuthResponse> {
        val result = authApi.register(request)

        // Update DataManager on success (same as login)
        if (result is ApiResult.Success) {
            DataManager.setAuthToken(result.data.token)
            DataManager.setCurrentUser(result.data.user)
            // Initialize lookups after successful registration
            initializeLookups()
            // Prefetch all data (user may have shared residences)
            prefetchAllData()
        }

        return result
    }

    suspend fun logout(): ApiResult<Unit> {
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        val result = authApi.logout(token)

        // Clear DataManager on logout (success or failure)
        DataManager.clear()

        return result
    }

    /**
     * Refresh the current auth token.
     * Calls POST /api/auth/refresh/ with the current token.
     * On success, saves the new token to DataManager and TokenStorage.
     * On failure, returns an error (caller decides whether to trigger logout).
     */
    suspend fun refreshToken(): ApiResult<String> {
        val currentToken = getToken() ?: return ApiResult.Error("No token", 401)
        val result = authApi.refreshToken(currentToken)
        if (result is ApiResult.Success) {
            DataManager.setAuthToken(result.data.token)
            com.tt.honeyDue.storage.TokenStorage.saveToken(result.data.token)
        }
        return when (result) {
            is ApiResult.Success -> ApiResult.Success(result.data.token)
            is ApiResult.Error -> ApiResult.Error(result.message, result.code)
            else -> ApiResult.Error("Unexpected state")
        }
    }

    suspend fun getCurrentUser(forceRefresh: Boolean = false): ApiResult<User> {
        // Check DataManager first
        if (!forceRefresh) {
            val cached = DataManager.currentUser.value
            if (cached != null) {
                return ApiResult.Success(cached)
            }
        }

        // Fetch from API
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        val result = authApi.getCurrentUser(token)

        // Update DataManager on success
        if (result is ApiResult.Success) {
            DataManager.setCurrentUser(result.data)
        }

        return result
    }

    suspend fun verifyEmail(token: String, request: VerifyEmailRequest): ApiResult<VerifyEmailResponse> {
        return authApi.verifyEmail(token, request)
    }

    suspend fun forgotPassword(request: ForgotPasswordRequest): ApiResult<ForgotPasswordResponse> {
        return authApi.forgotPassword(request)
    }

    suspend fun verifyResetCode(request: VerifyResetCodeRequest): ApiResult<VerifyResetCodeResponse> {
        return authApi.verifyResetCode(request)
    }

    suspend fun resetPassword(request: ResetPasswordRequest): ApiResult<ResetPasswordResponse> {
        return authApi.resetPassword(request)
    }

    suspend fun appleSignIn(request: AppleSignInRequest): ApiResult<AppleSignInResponse> {
        val result = authApi.appleSignIn(request)

        // Update DataManager on success
        if (result is ApiResult.Success) {
            DataManager.setAuthToken(result.data.token)
            DataManager.setCurrentUser(result.data.user)
            // Initialize lookups after successful Apple sign in
            initializeLookups()
            // Prefetch all data
            prefetchAllData()
        }

        return result
    }

    suspend fun googleSignIn(request: GoogleSignInRequest): ApiResult<GoogleSignInResponse> {
        val result = authApi.googleSignIn(request)

        // Update DataManager on success
        if (result is ApiResult.Success) {
            DataManager.setAuthToken(result.data.token)
            DataManager.setCurrentUser(result.data.user)
            // Initialize lookups after successful Google sign in
            initializeLookups()
            // Prefetch all data
            prefetchAllData()
        }

        return result
    }

    suspend fun updateProfile(token: String, request: UpdateProfileRequest): ApiResult<User> {
        val result = authApi.updateProfile(token, request)

        // Update DataManager on success
        if (result is ApiResult.Success) {
            DataManager.setCurrentUser(result.data)
        }

        return result
    }

    suspend fun deleteAccount(password: String? = null, confirmation: String? = null): ApiResult<Unit> {
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        val result = authApi.deleteAccount(token, DeleteAccountRequest(password = password, confirmation = confirmation))

        // Clear DataManager on successful deletion
        if (result is ApiResult.Success) {
            DataManager.clear()
        }

        return result
    }

    // ==================== Upload Operations ====================

    /**
     * Direct-to-B2 image upload. The bytes are POSTed straight to Backblaze
     * — they never touch our API server. Returns the pending_uploads.id
     * which the caller passes back via `upload_ids[]` on the next entity-
     * creation call (task completion, document, etc.).
     *
     * Caller responsibilities:
     *   - Pre-downsample to a sensible size before calling. Use the
     *     platform-specific ImageDownsampler (Android) or
     *     ImageDownsampler.swift (iOS).
     *   - Pass [contentType] matching the bytes (typically "image/jpeg").
     *   - Pass a [fileName] for B2's metadata. Need not be unique — the
     *     server picks the actual storage key.
     *
     * Errors at either step (presign or B2 POST) surface as ApiResult.Error.
     * Partial state (presign succeeded but B2 POST failed) is reaped by
     * the server-side cleanup cron within an hour.
     */
    suspend fun uploadImage(
        category: String,
        contentType: String,
        bytes: ByteArray,
        fileName: String,
    ): ApiResult<Int> {
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        return uploadApi.uploadOne(
            token = token,
            category = category,
            contentType = contentType,
            data = bytes,
            fileName = fileName,
        )
    }

    // ==================== Notification Operations ====================

    suspend fun registerDevice(request: DeviceRegistrationRequest): ApiResult<DeviceRegistrationResponse> {
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        return notificationApi.registerDevice(token, request)
    }

    suspend fun unregisterDevice(deviceId: Int): ApiResult<Unit> {
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        return notificationApi.unregisterDevice(token, deviceId)
    }

    suspend fun getNotificationPreferences(): ApiResult<NotificationPreference> {
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        val result = notificationApi.getNotificationPreferences(token)
        if (result is ApiResult.Success) DataManager.setNotificationPreferences(result.data)
        return result
    }

    suspend fun updateNotificationPreferences(request: UpdateNotificationPreferencesRequest): ApiResult<NotificationPreference> {
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        val result = notificationApi.updateNotificationPreferences(token, request)
        if (result is ApiResult.Success) DataManager.setNotificationPreferences(result.data)
        return result
    }

    suspend fun getNotificationHistory(): ApiResult<List<Notification>> {
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        return notificationApi.getNotificationHistory(token)
    }

    suspend fun markNotificationAsRead(notificationId: Int): ApiResult<MessageResponse> {
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        return notificationApi.markNotificationAsRead(token, notificationId)
    }

    suspend fun markAllNotificationsAsRead(): ApiResult<MessageResponse> {
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        return notificationApi.markAllNotificationsAsRead(token)
    }

    suspend fun getUnreadCount(): ApiResult<UnreadCountResponse> {
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        return notificationApi.getUnreadCount(token)
    }

    // ==================== Subscription Operations ====================

    /**
     * Get subscription status from backend.
     * Returns cached data from DataManager if available and forceRefresh is false.
     */
    suspend fun getSubscriptionStatus(forceRefresh: Boolean = false): ApiResult<SubscriptionStatus> {
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)

        // Return cached subscription if available and not forcing refresh
        if (!forceRefresh) {
            val cached = DataManager.subscription.value
            if (cached != null) {
                return ApiResult.Success(cached)
            }
        }

        val result = subscriptionApi.getSubscriptionStatus(token)

        // Update DataManager on success
        if (result is ApiResult.Success) {
            DataManager.setSubscription(result.data)
        }

        return result
    }

    /**
     * Verify Android purchase with backend
     */
    suspend fun verifyAndroidPurchase(purchaseToken: String, productId: String): ApiResult<VerificationResponse> {
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        return subscriptionApi.verifyAndroidPurchase(token, purchaseToken, productId)
    }

    /**
     * Verify iOS receipt with backend
     */
    suspend fun verifyIOSReceipt(receiptData: String, transactionId: String): ApiResult<VerificationResponse> {
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        return subscriptionApi.verifyIOSReceipt(token, receiptData, transactionId)
    }

    /**
     * Fetch feature benefits from backend (requires auth).
     */
    suspend fun getFeatureBenefits(): ApiResult<List<FeatureBenefit>> {
        val token = getToken() ?: return ApiResult.Error("Not authenticated", 401)
        val result = subscriptionApi.getFeatureBenefits(token)
        if (result is ApiResult.Success) {
            DataManager.setFeatureBenefits(result.data)
        }
        return result
    }

    // ==================== Helper Methods ====================

    /**
     * Prefetch all data after login.
     * Uses guards to prevent concurrent calls and skips if data is already cached.
     */
    private suspend fun prefetchAllData() {
        // Guard: prevent concurrent prefetch calls (thread-safe via Mutex)
        if (!prefetchMutex.tryLock()) {
            println("📋 [APILayer] Data prefetch already in progress, skipping...")
            return
        }

        try {
            // Skip if data is already cached (within cache validity period)
            val residencesCached = DataManager.isCacheValid(DataManager.myResidencesCacheTime) &&
                    DataManager.myResidences.value != null
            val tasksCached = DataManager.isCacheValid(DataManager.tasksCacheTime) &&
                    DataManager.allTasks.value != null

            if (residencesCached && tasksCached) {
                println("📋 [APILayer] Data already cached, skipping prefetch...")
                return
            }

            // Fetch key data - these all update DataManager
            if (!residencesCached) {
                getMyResidences(forceRefresh = true)
            }
            if (!tasksCached) {
                getTasks(forceRefresh = true)
            }
        } catch (e: Exception) {
            println("Error prefetching data: ${e.message}")
        } finally {
            prefetchMutex.unlock()
        }
    }
}
