package com.optix.android.domain.usecase

import com.google.gson.Gson
import com.optix.android.domain.model.ExportFormat
import com.optix.android.domain.model.Session
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
import javax.inject.Inject

/**
 * Renders saved [Session]s into shareable/exportable text in several formats.
 * - JSON: structured array, one object per session.
 * - CSV:  flat rows, results concatenated into a single quoted column.
 * - REPORT: human-readable markdown-style summary per session.
 */
class SessionExporter @Inject constructor(private val gson: Gson) {

    fun export(sessions: List<Session>, format: ExportFormat): String = when (format) {
        ExportFormat.JSON -> toJson(sessions)
        ExportFormat.CSV -> toCsv(sessions)
        ExportFormat.REPORT -> toReport(sessions)
    }

    fun toJson(sessions: List<Session>): String {
        val payload = mapOf(
            "app" to "Optix",
            "generatedAt" to System.currentTimeMillis(),
            "sessionCount" to sessions.size,
            "sessions" to sessions.map { it.toMap() },
        )
        return gson.toJson(payload)
    }

    fun toCsv(sessions: List<Session>): String {
        val header = listOf("timestamp", "tool", "params", "resultCount", "durationMs", "results")
        val rows = sessions.map { s ->
            listOf(
                fmtTime(s.createdAt),
                s.toolName,
                s.params.entries.joinToString("; ") { "${it.key}=${it.value}" },
                s.results.size.toString(),
                s.durationMs.toString(),
                s.results.joinToString(" | "),
            ).joinToString(",") { escapeCsv(it) }
        }
        return (listOf(header.joinToString(",")) + rows).joinToString("\n")
    }

    fun toReport(sessions: List<Session>): String = buildString {
        appendLine("# Optix Scan Report")
        appendLine("Generated: ${fmtTime(System.currentTimeMillis())}")
        appendLine("Sessions: ${sessions.size}")
        appendLine()
        sessions.forEachIndexed { i, s ->
            appendLine("## ${i + 1}. ${s.toolName}  (${fmtTime(s.createdAt)})")
            if (s.params.isNotEmpty()) {
                appendLine("Parameters:")
                s.params.forEach { (k, v) -> appendLine("  - $k = $v") }
            }
            appendLine("Duration: ${s.durationMs} ms")
            appendLine("Findings:")
            if (s.results.isEmpty()) {
                appendLine("  (none)")
            } else {
                s.results.forEach { line ->
                    val pretty = prettyResult(line)
                    appendLine("  - $pretty")
                }
            }
            appendLine()
        }
        appendLine("---")
        appendLine("Generated by Optix. Only use on systems you are authorized to test.")
    }

    // ── helpers ──────────────────────────────────────────────────────────────

    private fun Session.toMap(): Map<String, Any> = mapOf(
        "id" to id,
        "toolName" to toolName,
        "toolSlug" to toolSlug,
        "params" to params,
        "resultCount" to results.size,
        "durationMs" to durationMs,
        "createdAt" to createdAt,
        "results" to results,
        "logs" to logs,
    )

    private fun prettyResult(jsonLine: String): String {
        val type = runCatching { gson.fromJson(jsonLine, Map::class.java) as? Map<*, *> }.getOrNull()
        return if (type != null) {
            type.entries.joinToString("; ") { "${it.key}=${it.value}" }
        } else {
            jsonLine
        }
    }

    private fun escapeCsv(value: String): String {
        val needsQuote = value.contains(',') || value.contains('"') || value.contains('\n')
        val escaped = value.replace("\"", "\"\"")
        return if (needsQuote) "\"$escaped\"" else escaped
    }

    private fun fmtTime(ms: Long): String =
        SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).format(Date(ms))
}
