package com.correx.apps.server.tasks

import com.correx.core.tasks.ResolvedDocument
import com.correx.core.tasks.TaskDocumentResolver
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.nio.file.Files
import java.nio.file.Path
import kotlin.io.path.exists
import kotlin.io.path.isDirectory
import kotlin.io.path.isRegularFile
import kotlin.io.path.name
import kotlin.io.path.readText

private const val EXCERPT_MAX = 280
private val ADR_ID = Regex("(?i)^adr[-_ ]?0*(\\d+)$")
private val ADR_FILE = Regex("^adr-0*(\\d+)")
private val FRONTMATTER_NAME = Regex("(?m)^name:\\s*\"?(.+?)\"?\\s*$")
private val FRONTMATTER_DESC = Regex("(?m)^description:\\s*\"?(.+?)\"?\\s*$")

/**
 * Resolves link targets to repo documents for the task context bundle:
 *  - ADR ids ("adr-7", "ADR-0007", "adr 12") → `docs/decisions/adr-<n>-*.md` (matched by number,
 *    padding-agnostic);
 *  - explicit "*.md" paths under the repo root.
 * Title is the frontmatter `name:` or first `# ` heading; excerpt is the frontmatter
 * `description:` or the first prose paragraph, capped. Returns null for anything else.
 */
class FileTaskDocumentResolver(
    private val repoRoot: Path,
    private val decisionsDir: Path = repoRoot.resolve("docs/decisions"),
) : TaskDocumentResolver {

    override suspend fun resolve(targetId: String): ResolvedDocument? = withContext(Dispatchers.IO) {
        resolveAdr(targetId.trim()) ?: resolveMarkdownPath(targetId.trim())
    }

    private fun resolveAdr(targetId: String): ResolvedDocument? {
        val num = ADR_ID.matchEntire(targetId)?.groupValues?.get(1)?.toIntOrNull() ?: return null
        if (!decisionsDir.isDirectory()) return null
        val file = Files.list(decisionsDir).use { stream ->
            stream.filter { it.isRegularFile() && it.name.endsWith(".md") }
                .filter { adrNumber(it.name) == num }
                .findFirst()
                .orElse(null)
        } ?: return null
        return readDocument(file)
    }

    private fun resolveMarkdownPath(targetId: String): ResolvedDocument? {
        if (!targetId.endsWith(".md")) return null
        val candidate = repoRoot.resolve(targetId).normalize()
        if (!candidate.startsWith(repoRoot) || !candidate.exists() || !candidate.isRegularFile()) return null
        return readDocument(candidate)
    }

    private fun adrNumber(fileName: String): Int? =
        ADR_FILE.find(fileName.lowercase())?.groupValues?.get(1)?.toIntOrNull()

    private fun readDocument(file: Path): ResolvedDocument {
        val text = runCatching { file.readText() }.getOrDefault("")
        return ResolvedDocument(
            title = extractTitle(text) ?: file.name,
            path = repoRoot.relativize(file).toString(),
            excerpt = extractExcerpt(text),
        )
    }

    private fun extractTitle(text: String): String? {
        FRONTMATTER_NAME.find(text)?.groupValues?.get(1)?.trim()?.takeIf { it.isNotBlank() }?.let { return it }
        return text.lineSequence().firstOrNull { it.startsWith("# ") }?.removePrefix("# ")?.trim()
    }

    private fun extractExcerpt(text: String): String {
        val desc = FRONTMATTER_DESC.find(text)?.groupValues?.get(1)?.trim()
        return (desc ?: firstParagraph(text)).take(EXCERPT_MAX).trim()
    }

    private fun firstParagraph(text: String): String =
        stripFrontmatter(text).lineSequence()
            .map { it.trim() }
            .firstOrNull { it.isNotEmpty() && !it.startsWith("#") && !it.startsWith("---") }
            ?: ""

    private fun stripFrontmatter(text: String): String {
        if (!text.startsWith("---")) return text
        val lines = text.lines()
        val closeIdx = lines.drop(1).indexOfFirst { it.trim() == "---" }
        return if (closeIdx >= 0) lines.drop(closeIdx + 2).joinToString("\n") else text
    }
}
