package com.correx.infrastructure.workflow

import java.nio.file.FileSystems
import java.nio.file.Path
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue

class PlanDerivedManifestTest {

    @Test
    fun `derives the declared write paths of a plan stage`() {
        val stage = PlanStage(id = "impl", writes = listOf("core/a/B.kt", "docs/notes.md"))
        assertEquals(setOf("core/a/B.kt", "docs/notes.md"), PlanDerivedManifest.deriveAllowedWrites(stage))
    }

    @Test
    fun `a stage with no declared writes derives an empty set`() {
        val stage = PlanStage(id = "analyse", produces = "patch", needs = listOf("x"))
        assertTrue(PlanDerivedManifest.deriveAllowedWrites(stage).isEmpty())
    }

    @Test
    fun `multiple files are all derived and blank entries dropped`() {
        val stage = PlanStage(id = "impl", writes = listOf("a.kt", "  ", "b.kt", "", "c.kt"))
        assertEquals(setOf("a.kt", "b.kt", "c.kt"), PlanDerivedManifest.deriveAllowedWrites(stage))
    }

    @Test
    fun `combine unions the static globs with the plan-derived set`() {
        val combined = PlanDerivedManifest.combine(
            staticManifest = listOf("core/**"),
            planDerived = setOf("docs/x.md"),
        )
        assertEquals(setOf("core/**", "docs/x.md"), combined)
    }

    @Test
    fun `combine drops blank entries and de-duplicates across sources`() {
        val combined = PlanDerivedManifest.combine(
            staticManifest = listOf("core/**", "  ", "shared.kt"),
            planDerived = setOf("shared.kt", "docs/x.md", ""),
        )
        assertEquals(setOf("core/**", "shared.kt", "docs/x.md"), combined)
    }

    @Test
    fun `combined manifest matches via the same glob semantics the static manifest uses`() {
        // The combined set is fed verbatim into StageConfig.writeManifest, which the plane-2
        // ManifestContainmentRule matches with FileSystems glob PathMatchers. Assert that a write
        // allowed only by the plan-derived entry, one allowed only by the static glob, and one in
        // neither resolve as expected under that exact matcher — no parallel matcher is introduced.
        val combined = PlanDerivedManifest.combine(
            staticManifest = listOf("core/**"),
            planDerived = setOf("docs/x.md"),
        )
        val matchers = combined.map { FileSystems.getDefault().getPathMatcher("glob:$it") }
        fun allowed(rel: String) = matchers.any { it.matches(Path.of(rel)) }

        assertTrue(allowed("core/a/B.kt"), "static glob should allow core/a/B.kt")
        assertTrue(allowed("docs/x.md"), "plan-derived path should allow docs/x.md")
        assertFalse(allowed("apps/server/Main.kt"), "a path in neither source is denied")
    }
}
