package de.hoennig.werkator.server

import com.ninjasquad.springmockk.MockkBean
import de.hoennig.werkator.build.ArtifactStore
import de.hoennig.werkator.build.BuildExecutor
import de.hoennig.werkator.build.BuildResult
import de.hoennig.werkator.build.BuildResultRepository
import de.hoennig.werkator.build.BuildStatus
import de.hoennig.werkator.config.ConfigLoader
import de.hoennig.werkator.config.WerkatorConfig
import de.hoennig.werkator.git.GitService
import de.hoennig.werkator.metrics.SystemMetricsCollector
import de.hoennig.werkator.repo.RepoContext
import de.hoennig.werkator.repo.RepoLinks
import de.hoennig.werkator.repo.RepoRegistry
import io.kotest.core.spec.style.FunSpec
import io.mockk.clearMocks
import io.mockk.every
import org.hamcrest.Matchers.containsString
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest
import org.springframework.context.annotation.Import
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.content
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths
import java.time.Duration
import java.time.Instant

/**
 * The three `/branches…` routes live in two controllers; this slice registers both
 * and proves the mappings coexist: the exact list page, the permanent index page,
 * and the catch-all permanent file route.
 */
@WebMvcTest(
    controllers = [UiController::class, ArtifactFileController::class],
    properties = ["spring.main.web-application-type=servlet"],
)
@Import(RepoLinks::class)
class PermanentBranchRoutesTest : FunSpec() {
    @Autowired
    lateinit var mockMvc: MockMvc

    @MockkBean
    lateinit var repository: BuildResultRepository

    @MockkBean
    lateinit var buildExecutor: BuildExecutor

    @MockkBean
    lateinit var artifactStore: ArtifactStore

    @MockkBean
    lateinit var controlTokens: ControlTokenService

    @MockkBean
    lateinit var configLoader: ConfigLoader

    @MockkBean
    lateinit var gitService: GitService

    @MockkBean
    lateinit var metricsCollector: SystemMetricsCollector

    @MockkBean
    lateinit var branchListing: BranchListing

    @MockkBean
    lateinit var branchPermalinks: BranchPermalinks

    @MockkBean
    lateinit var repo: RepoContext

    @MockkBean
    lateinit var registry: RepoRegistry

    private val artifactDir: Path = Files.createTempDirectory("werkator-permanent-routes-test")

    private val greenBuild =
        BuildResult(
            branch = "main",
            commit = "0123456789abcdef",
            status = BuildStatus.SUCCESS,
            startedAt = Instant.parse("2026-07-07T10:00:00Z"),
            duration = Duration.ofSeconds(83),
            artifactKey = "main-key",
        )

    init {
        beforeEach {
            clearMocks(
                repository,
                buildExecutor,
                artifactStore,
                controlTokens,
                configLoader,
                gitService,
                metricsCollector,
                branchListing,
                branchPermalinks,
                repo,
                registry,
            )
            every { repo.name } returns "test"
            every { repo.workingDir } returns Paths.get(".")
            every { repo.results } returns repository
            every { repo.artifactStore } returns artifactStore
            every { registry.all() } returns listOf(repo)
            every { registry.current() } returns repo
            every { registry.byName(any()) } returns null
            every { registry.byName("test") } returns repo
            every { configLoader.load(any()) } returns WerkatorConfig()
            every { configLoader.loadWithBranchLayer(any(), anyNullable()) } returns WerkatorConfig()
            every { gitService.showFileAtCommit(any(), any(), any()) } returns null
            every { controlTokens.token() } returns "test-token"
            every { branchListing.branches(any()) } returns emptyList()
            every { branchPermalinks.latestGreenBuild(any(), "main") } returns greenBuild
            every { artifactStore.artifactDir("main-key") } returns artifactDir
        }

        test("/branches still renders the branch list page") {
            mockMvc
                .perform(get("/branches"))
                .andExpect(status().isOk)
                .andExpect(content().string(containsString("""data-api="/api/branches"""")))
        }

        test("/branches/<key> renders the permanent artifact index page") {
            mockMvc
                .perform(get("/branches/main"))
                .andExpect(status().isOk)
                .andExpect(content().string(containsString("latest green build of branch")))
        }

        test("/branches/<key>/<path> serves the artifact file") {
            Files.writeString(artifactDir.resolve("build.log"), "line one")

            mockMvc
                .perform(get("/branches/main/build.log"))
                .andExpect(status().isOk)
                .andExpect(content().string("line one"))
        }
    }
}
