package wang.yaojia.webterm.clienttls

import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertFalse
import org.junit.jupiter.api.Assertions.assertNotNull
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test
import java.time.Instant
import kotlin.time.Duration.Companion.days

/** Ports iOS `CertificateSummary` tests — field extraction off a real cert + the isExpired rule. */
class CertificateSummaryTest {
    private fun leafSummary(): CertificateSummary =
        Pkcs12Parse.parse(Fixtures.leafP12(), Fixtures.PASSPHRASE).summary()

    @Test
    fun extractsSubjectAndIssuerCommonNamesFromRealCertificate() {
        val summary = leafSummary()
        assertEquals(Fixtures.LEAF_SUBJECT_CN, summary.subjectCommonName)
        assertEquals(Fixtures.LEAF_ISSUER_CN, summary.issuerCommonName)
    }

    @Test
    fun extractsNotAfterFromRealCertificate() {
        val summary = leafSummary()
        assertNotNull(summary.notAfter, "notAfter should parse off the fixture cert")
        // Fixture was minted with a ~100-year validity, so it is not expired now.
        assertFalse(summary.isExpired(Instant.now()))
    }

    @Test
    fun isExpiredIsTrueStrictlyAfterNotAfter() {
        val notAfter = Instant.parse("2030-01-01T00:00:00Z")
        val summary = CertificateSummary(subjectCommonName = "x", issuerCommonName = "y", notAfter = notAfter)

        assertFalse(summary.isExpired(notAfter.minusMillis(1)), "just before expiry")
        assertFalse(summary.isExpired(notAfter), "exactly at notAfter is not yet expired")
        assertTrue(summary.isExpired(notAfter.plusMillis(1)), "just after expiry")
        assertTrue(summary.isExpired(notAfter.plusSeconds(365.days.inWholeSeconds)), "well after expiry")
    }

    @Test
    fun unknownExpiryFailsOpenAsNotExpired() {
        val summary = CertificateSummary(subjectCommonName = null, issuerCommonName = null, notAfter = null)
        assertFalse(summary.isExpired(Instant.now()), "null notAfter is display-only fail-open → not expired")
    }

    @Test
    fun realCertificateNotAfterMatchesLeafExpiry() {
        // Derive isExpired boundaries from the parsed notAfter so the test stays deterministic
        // regardless of the fixture generation date.
        val summary = leafSummary()
        val notAfter = requireNotNull(summary.notAfter)
        assertFalse(summary.isExpired(notAfter.minusSeconds(1)))
        assertTrue(summary.isExpired(notAfter.plusSeconds(1)))
    }

    @Test
    fun summaryFromCertificateReaderMatchesParsedLeaf() {
        val identity = Pkcs12Parse.parse(Fixtures.leafP12(), Fixtures.PASSPHRASE)
        val direct = CertificateSummaryReader.summarize(identity.leafCertificate)
        assertEquals(identity.summary(), direct)
    }
}
