import Foundation

/// Renders a full session — metadata, backend/debug fields, the human-readable
/// conversation, and the raw event JSONL — into a single Markdown document for
/// sharing as a reference.
public enum ConversationExport {
    public static func markdown(session: Session, project: Project?, events: [AgentEvent]) -> String {
        var out = "# Nucleic session export\n\n"

        out += "## Session\n"
        out += line("Title", session.title)
        out += line("ID", session.id.rawValue)
        out += line("Status", session.status.displayName)
        out += line("Backend", session.backend.rawValue)
        out += line("Backend session id", session.backendSessionID ?? "—")
        out += line("Model", session.model ?? "default")
        out += line("Effort", session.effort ?? "default")
        out += line("Branch", session.branch ?? "—")
        out += line("Worktree", session.worktreePath ?? "—")
        out += line("Base SHA", session.baseSHA ?? "—")
        if let diff = session.diffStat {
            out += line("Diff", "\(diff.filesChanged) files +\(diff.added) −\(diff.removed)")
        }
        out += line("Last seq", "\(session.lastSeq)")
        out += line("Transcript path", session.transcriptPath)
        out += line("Created", iso(session.createdAt))
        out += line("Updated", iso(session.updatedAt))

        if let project {
            out += "\n## Project\n"
            out += line("Name", project.name)
            out += line("Root", project.rootPath)
            out += line("Default branch", project.defaultBranch.value)
        }

        out += "\n## Conversation\n\n"
        for event in events { out += human(event) }

        out += "\n## Raw events (JSONL)\n\nFull normalized event stream for debugging:\n\n```jsonl\n"
        let encoder = JSONEncoder()
        encoder.outputFormatting = [.sortedKeys, .withoutEscapingSlashes]
        encoder.dateEncodingStrategy = .iso8601
        for event in events {
            if let data = try? encoder.encode(event) {
                out += String(decoding: data, as: UTF8.self) + "\n"
            }
        }
        out += "```\n"
        return out
    }

    /// A filesystem-safe default filename for the export.
    public static func suggestedFileName(for session: Session) -> String {
        let slug = Slug.sanitize(session.title, fallback: "session")
        return "nucleic-\(slug)-\(session.id.short).md"
    }

    // MARK: - rendering

    private static func line(_ key: String, _ value: String) -> String { "- **\(key):** \(value)\n" }

    private static func human(_ event: AgentEvent) -> String {
        let seq = "`#\(event.seq)`"
        switch event.kind {
        case .sessionStarted(let started):
            return "\(seq) **session started** — model \(started.model)\n\n"
        case .userText(let chunk):
            return "\(seq) **User:** \(chunk.text)\n\n"
        case .assistantText(let chunk) where !chunk.isPartial:
            return "\(seq) **Assistant:** \(chunk.text)\n\n"
        case .assistantText, .thinking, .toolCallInputDelta:
            return ""
        case .toolCallCompleted(let call):
            return "\(seq) **Tool** `\(call.name)` — \(call.input.canonicalString())\n\n"
        case .toolCallStarted:
            return ""
        case .toolResult(let result):
            let body = result.content.canonicalString()
            return "\(seq) **Result**\(result.isError ? " (error)" : ""): \(body.prefix(2000))\n\n"
        case .fileChange(let change):
            return "\(seq) **File \(change.kind.rawValue):** \(change.path)\n\n"
        case .approvalRequested(let request):
            return "\(seq) **Approval requested:** \(request.title) [\(request.risk.rawValue)]\n\n"
        case .approvalResolved(let resolved):
            return "\(seq) **Approval \(resolved.decidedBy):** resolved\n\n"
        case .usage(let usage):
            return "\(seq) _usage in=\(usage.inputTokens ?? 0) out=\(usage.outputTokens ?? 0)_\n\n"
        case .rateLimit(let rl):
            return "\(seq) _rate limit \(rl.rateLimitType ?? "?") \(rl.status ?? "")_\n\n"
        case .turnCompleted:
            return "\(seq) _— turn completed —_\n\n"
        case .runFinished(let finished):
            return "\(seq) _— run \(finished.outcome.rawValue) —_\n\n"
        case .error(let error):
            return "\(seq) ⚠️ **\(error.recoverable ? "recoverable" : "fatal")**: \(error.message)\n\n"
        case .note(let note):
            return "\(seq) _\(note.text)_\n\n"
        case .raw(let raw):
            return "\(seq) `raw[\(event.nativeType ?? "?")]` \(raw.native.canonicalString().prefix(500))\n\n"
        }
    }

    private static func iso(_ date: Date) -> String {
        let formatter = ISO8601DateFormatter()
        return formatter.string(from: date)
    }
}
