package org.timesafari.dailynotification

import android.content.Context
import androidx.test.core.app.ApplicationProvider
import kotlinx.coroutines.runBlocking
import org.json.JSONObject
import org.junit.After
import org.junit.Assert.assertFalse
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
import kotlin.text.Charsets

@RunWith(RobolectricTestRunner::class)
@Config(sdk = [28])
class DualScheduleHelperTest {

    private lateinit var context: Context

    @Before
    fun setUp() {
        context = ApplicationProvider.getApplicationContext()
        context.getSharedPreferences(DailyNotificationConstants.DUAL_SCHEDULE_PREFS, Context.MODE_PRIVATE)
            .edit()
            .clear()
            .commit()
        runBlocking {
            DailyNotificationDatabase.getDatabase(context).contentCacheDao().deleteAll()
        }
    }

    @After
    fun tearDown() {
        context.getSharedPreferences(DailyNotificationConstants.DUAL_SCHEDULE_PREFS, Context.MODE_PRIVATE)
            .edit()
            .clear()
            .commit()
        runBlocking {
            DailyNotificationDatabase.getDatabase(context).contentCacheDao().deleteAll()
        }
    }

    @Test
    fun freshCache_skipNotification_returnsNull_evenWithShowDefault() {
        putDualConfig("""{"fallbackBehavior":"show_default","contentTimeout":600000}""")
        insertDualCache(
            payload = FetchWorker.dualEmptyNativeFetchPayload,
            fetchedAt = System.currentTimeMillis()
        )
        assertNull(DualScheduleHelper.resolveDualContentBlocking(context, "dual_notify_test"))
    }

    @Test
    fun freshCache_skipNotification_returnsNull_withSkipFallback() {
        putDualConfig("""{"fallbackBehavior":"skip","contentTimeout":600000}""")
        insertDualCache(
            payload = FetchWorker.dualEmptyNativeFetchPayload,
            fetchedAt = System.currentTimeMillis()
        )
        assertNull(DualScheduleHelper.resolveDualContentBlocking(context, "dual_notify_test"))
    }

    @Test
    fun staleCache_skipNotification_skipFallback_returnsNull() {
        putDualConfig("""{"fallbackBehavior":"skip","contentTimeout":1000}""")
        insertDualCache(
            payload = FetchWorker.dualEmptyNativeFetchPayload,
            fetchedAt = System.currentTimeMillis() - 60_000L
        )
        assertNull(DualScheduleHelper.resolveDualContentBlocking(context, "dual_notify_test"))
    }

    @Test
    fun staleCache_skipNotification_showDefault_usesUserDefaults() {
        putDualConfig("""{"fallbackBehavior":"show_default","contentTimeout":1000}""")
        insertDualCache(
            payload = FetchWorker.dualEmptyNativeFetchPayload,
            fetchedAt = System.currentTimeMillis() - 60_000L
        )
        val content = DualScheduleHelper.resolveDualContentBlocking(context, "dual_notify_test")
        assertNotNull(content)
        assertTrue(content!!.title == "New Activity")
    }

    @Test
    fun freshCache_realPayload_returnsContent() {
        putDualConfig("""{"fallbackBehavior":"skip","contentTimeout":600000}""")
        val json = JSONObject()
        json.put("title", "API Title")
        json.put("body", "API Body")
        insertDualCache(
            payload = json.toString().toByteArray(Charsets.UTF_8),
            fetchedAt = System.currentTimeMillis()
        )
        val content = DualScheduleHelper.resolveDualContentBlocking(context, "dual_notify_test")
        assertNotNull(content)
        assertTrue(content!!.title == "API Title" && content.body == "API Body")
    }

    @Test
    fun isDualSkipNotificationPayload_emptyObject_false() {
        assertFalse(FetchWorker.isDualSkipNotificationPayload("{}".toByteArray(Charsets.UTF_8)))
    }

    @Test
    fun isDualSkipNotificationPayload_sentinel_true() {
        assertTrue(FetchWorker.isDualSkipNotificationPayload(FetchWorker.dualEmptyNativeFetchPayload))
    }

    private fun putDualConfig(relationshipJson: String) {
        val root = JSONObject()
        val user = JSONObject()
        user.put("enabled", true)
        user.put("schedule", "0 9 * * *")
        user.put("title", "New Activity")
        user.put("body", "Check your starred projects for updates")
        root.put("userNotification", user)
        root.put("relationship", JSONObject(relationshipJson))
        context.getSharedPreferences(DailyNotificationConstants.DUAL_SCHEDULE_PREFS, Context.MODE_PRIVATE)
            .edit()
            .putString(DailyNotificationConstants.DUAL_SCHEDULE_CONFIG_KEY, root.toString())
            .commit()
    }

    private fun insertDualCache(payload: ByteArray, fetchedAt: Long) {
        val cache = ContentCache(
            id = "test_dual_${System.nanoTime()}",
            fetchedAt = fetchedAt,
            ttlSeconds = 3600,
            payload = payload,
            meta = "test",
            cacheScope = ContentCacheScope.DUAL
        )
        runBlocking {
            DailyNotificationDatabase.getDatabase(context).contentCacheDao().upsert(cache)
        }
    }
}
