// Show the contents of a file, if possible.

import { escapeHTML } from "bun"
import { readdirSync } from "fs"
import { join, extname } from "path"

import type { CommandOutput } from "@/shared/types"
import { isBinaryFile } from "@/utils"
import { projectDir } from "@/project"
import { sessionGet } from "@/session"
import { highlight } from "../lib/highlight"

export default async function (path: string) {
    const root = sessionGet("cwd") || projectDir()

    let files: string[] = []

    for (const file of readdirSync(root, { withFileTypes: true })) {
        files.push(file.name)
    }

    if (!files.includes(path))
        return { error: `file not found: ${path}` }

    return await readFile(join(root, path))
}

async function readFile(path: string): Promise<CommandOutput> {
    const ext = extname(path).slice(1)
    const file = Bun.file(path)

    switch (ext) {
        case "jpeg": case "jpg": case "png": case "gif": case "webp":
            const img = await file.arrayBuffer()
            return { html: `<img src="data:image/${ext};base64,${Buffer.from(img).toString('base64')}" style="max-height:270px;max-width:480px;" />` }
        case "mp3": case "wav":
        case "mp4": case "mov": case "avi": case "mkv": case "webm":
            return "Not implemented"
        case "js": case "ts": case "tsx": case "json":
            return {
                html: `<div style='white-space: pre;'>${highlight(convertIndent(await file.text()))}</div>`
            }
        default:
            if (await isBinaryFile(path))
                throw "Cannot display binary file"

            return {
                html: `<div style="white-space: pre;">${escapeHTML(await file.text())}</div>`
            }
    }
}

// cut down 4space and 2space indents into 1space, for readability on a small screen
function convertIndent(str: string) {
    const lines = str.split("\n")

    // find the smallest non-zero indent
    const minIndent = Math.min(
        ...lines
            .map(l => (l.match(/^ +/) || [""])[0].length)
            .filter(len => len > 0)
    )

    return lines
        .map(line =>
            line.replace(/^( +)/, (_, spaces) => " ".repeat(spaces.length / minIndent))
        )
        .join("\n")
}

