package com.swoosh.microblog.data.repository

import com.swoosh.microblog.data.model.*
import org.junit.Assert.*
import org.junit.Test
import java.time.Instant
import java.time.temporal.ChronoUnit

class MemberRepositoryTest {

    // We test getMemberStats() which is a pure function — no Context needed
    private fun createRepository(): MemberRepository? = null // Can't instantiate without Context

    private fun getMemberStats(members: List<GhostMember>): MemberStats {
        // Replicate the pure function logic to test it directly
        // We use a standalone helper since the repository needs Context
        val total = members.size
        val free = members.count { it.status == "free" }
        val paid = members.count { it.status == "paid" }

        val oneWeekAgo = Instant.now().minus(7, ChronoUnit.DAYS)
        val newThisWeek = members.count { member ->
            member.created_at?.let {
                try {
                    Instant.parse(it).isAfter(oneWeekAgo)
                } catch (e: Exception) {
                    false
                }
            } ?: false
        }

        val openRates = members.mapNotNull { it.email_open_rate }
        val avgOpenRate = if (openRates.isNotEmpty()) openRates.average() else null

        val mrr = members.filter { it.status == "paid" }.sumOf { member ->
            member.subscriptions?.sumOf { sub ->
                if (sub.status == "active") {
                    val amount = sub.price?.amount ?: 0
                    when (sub.price?.interval) {
                        "year" -> amount / 12
                        "month" -> amount
                        else -> amount
                    }
                } else 0
            } ?: 0
        }

        return MemberStats(
            total = total, free = free, paid = paid,
            newThisWeek = newThisWeek, avgOpenRate = avgOpenRate, mrr = mrr
        )
    }

    private fun makeMember(
        id: String = "m1",
        email: String? = null,
        name: String? = null,
        status: String? = "free",
        openRate: Double? = null,
        createdAt: String? = null,
        subscriptions: List<MemberSubscription>? = null
    ) = GhostMember(
        id = id, email = email, name = name, status = status,
        avatar_image = null, email_count = null, email_opened_count = null,
        email_open_rate = openRate, last_seen_at = null,
        created_at = createdAt, updated_at = null,
        labels = null, newsletters = null, subscriptions = subscriptions,
        note = null, geolocation = null
    )

    @Test
    fun `getMemberStats with empty list returns zero stats`() {
        val stats = getMemberStats(emptyList())
        assertEquals(0, stats.total)
        assertEquals(0, stats.free)
        assertEquals(0, stats.paid)
        assertEquals(0, stats.newThisWeek)
        assertNull(stats.avgOpenRate)
        assertEquals(0, stats.mrr)
    }

    @Test
    fun `getMemberStats counts total members`() {
        val members = listOf(
            makeMember(id = "m1"),
            makeMember(id = "m2"),
            makeMember(id = "m3")
        )
        val stats = getMemberStats(members)
        assertEquals(3, stats.total)
    }

    @Test
    fun `getMemberStats counts free and paid members`() {
        val members = listOf(
            makeMember(id = "m1", status = "free"),
            makeMember(id = "m2", status = "free"),
            makeMember(id = "m3", status = "paid"),
            makeMember(id = "m4", status = "paid"),
            makeMember(id = "m5", status = "paid")
        )
        val stats = getMemberStats(members)
        assertEquals(5, stats.total)
        assertEquals(2, stats.free)
        assertEquals(3, stats.paid)
    }

    @Test
    fun `getMemberStats counts new members this week`() {
        val recentDate = Instant.now().minus(2, ChronoUnit.DAYS).toString()
        val oldDate = Instant.now().minus(30, ChronoUnit.DAYS).toString()
        val members = listOf(
            makeMember(id = "m1", createdAt = recentDate),
            makeMember(id = "m2", createdAt = recentDate),
            makeMember(id = "m3", createdAt = oldDate)
        )
        val stats = getMemberStats(members)
        assertEquals(2, stats.newThisWeek)
    }

    @Test
    fun `getMemberStats handles null created_at for new this week`() {
        val members = listOf(
            makeMember(id = "m1", createdAt = null),
            makeMember(id = "m2", createdAt = null)
        )
        val stats = getMemberStats(members)
        assertEquals(0, stats.newThisWeek)
    }

    @Test
    fun `getMemberStats handles invalid created_at date`() {
        val members = listOf(
            makeMember(id = "m1", createdAt = "not-a-date")
        )
        val stats = getMemberStats(members)
        assertEquals(0, stats.newThisWeek)
    }

    @Test
    fun `getMemberStats calculates average open rate`() {
        val members = listOf(
            makeMember(id = "m1", openRate = 40.0),
            makeMember(id = "m2", openRate = 60.0),
            makeMember(id = "m3", openRate = 80.0)
        )
        val stats = getMemberStats(members)
        assertNotNull(stats.avgOpenRate)
        assertEquals(60.0, stats.avgOpenRate!!, 0.001)
    }

    @Test
    fun `getMemberStats skips null open rates in average`() {
        val members = listOf(
            makeMember(id = "m1", openRate = 50.0),
            makeMember(id = "m2", openRate = null),
            makeMember(id = "m3", openRate = 100.0)
        )
        val stats = getMemberStats(members)
        assertNotNull(stats.avgOpenRate)
        assertEquals(75.0, stats.avgOpenRate!!, 0.001) // (50 + 100) / 2
    }

    @Test
    fun `getMemberStats returns null avgOpenRate when all rates are null`() {
        val members = listOf(
            makeMember(id = "m1", openRate = null),
            makeMember(id = "m2", openRate = null)
        )
        val stats = getMemberStats(members)
        assertNull(stats.avgOpenRate)
    }

    @Test
    fun `getMemberStats calculates MRR from monthly subscriptions`() {
        val members = listOf(
            makeMember(
                id = "m1", status = "paid",
                subscriptions = listOf(
                    MemberSubscription(
                        id = "s1", status = "active", start_date = null,
                        current_period_end = null, cancel_at_period_end = false,
                        price = SubscriptionPrice(amount = 500, currency = "USD", interval = "month"),
                        tier = null
                    )
                )
            ),
            makeMember(
                id = "m2", status = "paid",
                subscriptions = listOf(
                    MemberSubscription(
                        id = "s2", status = "active", start_date = null,
                        current_period_end = null, cancel_at_period_end = false,
                        price = SubscriptionPrice(amount = 1000, currency = "USD", interval = "month"),
                        tier = null
                    )
                )
            )
        )
        val stats = getMemberStats(members)
        assertEquals(1500, stats.mrr) // 500 + 1000
    }

    @Test
    fun `getMemberStats converts yearly subscriptions to monthly MRR`() {
        val members = listOf(
            makeMember(
                id = "m1", status = "paid",
                subscriptions = listOf(
                    MemberSubscription(
                        id = "s1", status = "active", start_date = null,
                        current_period_end = null, cancel_at_period_end = false,
                        price = SubscriptionPrice(amount = 12000, currency = "USD", interval = "year"),
                        tier = null
                    )
                )
            )
        )
        val stats = getMemberStats(members)
        assertEquals(1000, stats.mrr) // 12000 / 12
    }

    @Test
    fun `getMemberStats ignores canceled subscriptions in MRR`() {
        val members = listOf(
            makeMember(
                id = "m1", status = "paid",
                subscriptions = listOf(
                    MemberSubscription(
                        id = "s1", status = "canceled", start_date = null,
                        current_period_end = null, cancel_at_period_end = true,
                        price = SubscriptionPrice(amount = 500, currency = "USD", interval = "month"),
                        tier = null
                    )
                )
            )
        )
        val stats = getMemberStats(members)
        assertEquals(0, stats.mrr)
    }

    @Test
    fun `getMemberStats ignores free members in MRR calculation`() {
        val members = listOf(
            makeMember(id = "m1", status = "free"),
            makeMember(
                id = "m2", status = "paid",
                subscriptions = listOf(
                    MemberSubscription(
                        id = "s1", status = "active", start_date = null,
                        current_period_end = null, cancel_at_period_end = false,
                        price = SubscriptionPrice(amount = 500, currency = "USD", interval = "month"),
                        tier = null
                    )
                )
            )
        )
        val stats = getMemberStats(members)
        assertEquals(500, stats.mrr)
    }

    @Test
    fun `getMemberStats handles paid member with no subscriptions`() {
        val members = listOf(
            makeMember(id = "m1", status = "paid", subscriptions = null)
        )
        val stats = getMemberStats(members)
        assertEquals(1, stats.paid)
        assertEquals(0, stats.mrr)
    }

    @Test
    fun `getMemberStats handles paid member with empty subscriptions`() {
        val members = listOf(
            makeMember(id = "m1", status = "paid", subscriptions = emptyList())
        )
        val stats = getMemberStats(members)
        assertEquals(1, stats.paid)
        assertEquals(0, stats.mrr)
    }

    @Test
    fun `getMemberStats mixed free and paid members comprehensive`() {
        val recentDate = Instant.now().minus(1, ChronoUnit.DAYS).toString()
        val oldDate = Instant.now().minus(60, ChronoUnit.DAYS).toString()

        val members = listOf(
            makeMember(id = "m1", status = "free", openRate = 40.0, createdAt = recentDate),
            makeMember(id = "m2", status = "free", openRate = 60.0, createdAt = oldDate),
            makeMember(
                id = "m3", status = "paid", openRate = 80.0, createdAt = recentDate,
                subscriptions = listOf(
                    MemberSubscription(
                        id = "s1", status = "active", start_date = null,
                        current_period_end = null, cancel_at_period_end = false,
                        price = SubscriptionPrice(amount = 500, currency = "USD", interval = "month"),
                        tier = SubscriptionTier(id = "t1", name = "Gold")
                    )
                )
            ),
            makeMember(
                id = "m4", status = "paid", openRate = null, createdAt = oldDate,
                subscriptions = listOf(
                    MemberSubscription(
                        id = "s2", status = "active", start_date = null,
                        current_period_end = null, cancel_at_period_end = false,
                        price = SubscriptionPrice(amount = 6000, currency = "USD", interval = "year"),
                        tier = SubscriptionTier(id = "t1", name = "Gold")
                    )
                )
            )
        )

        val stats = getMemberStats(members)
        assertEquals(4, stats.total)
        assertEquals(2, stats.free)
        assertEquals(2, stats.paid)
        assertEquals(2, stats.newThisWeek) // m1 and m3
        assertEquals(60.0, stats.avgOpenRate!!, 0.001) // (40 + 60 + 80) / 3
        assertEquals(1000, stats.mrr) // 500 + 6000/12 = 500 + 500
    }

    @Test
    fun `getMemberStats handles null status members`() {
        val members = listOf(
            makeMember(id = "m1", status = null),
            makeMember(id = "m2", status = "free")
        )
        val stats = getMemberStats(members)
        assertEquals(2, stats.total)
        assertEquals(1, stats.free)
        assertEquals(0, stats.paid)
    }

    @Test
    fun `getMemberStats handles subscription with null price`() {
        val members = listOf(
            makeMember(
                id = "m1", status = "paid",
                subscriptions = listOf(
                    MemberSubscription(
                        id = "s1", status = "active", start_date = null,
                        current_period_end = null, cancel_at_period_end = false,
                        price = null, tier = null
                    )
                )
            )
        )
        val stats = getMemberStats(members)
        assertEquals(0, stats.mrr)
    }

    @Test
    fun `getMemberStats handles subscription with null amount`() {
        val members = listOf(
            makeMember(
                id = "m1", status = "paid",
                subscriptions = listOf(
                    MemberSubscription(
                        id = "s1", status = "active", start_date = null,
                        current_period_end = null, cancel_at_period_end = false,
                        price = SubscriptionPrice(amount = null, currency = "USD", interval = "month"),
                        tier = null
                    )
                )
            )
        )
        val stats = getMemberStats(members)
        assertEquals(0, stats.mrr)
    }
}
