import { existsSync, readdirSync, readFileSync, writeFileSync } from "node:fs"
import { join } from "node:path"

import { getMessageIds } from "./message-storage-directory"
import { PART_STORAGE_DIR, TRUNCATION_MESSAGE } from "./storage-paths"
import type { StoredToolPart, ToolResultInfo } from "./tool-part-types"
import { isSqliteBackend } from "../../shared/opencode-storage-detection"
import { log } from "../../shared/logger"

let hasLoggedTruncateWarning = false

export function findToolResultsBySize(sessionID: string): ToolResultInfo[] {
	const messageIds = getMessageIds(sessionID)
	const results: ToolResultInfo[] = []

	for (const messageID of messageIds) {
		const partDir = join(PART_STORAGE_DIR, messageID)
		if (!existsSync(partDir)) continue

		for (const file of readdirSync(partDir)) {
			if (!file.endsWith(".json")) continue
			try {
				const partPath = join(partDir, file)
				const content = readFileSync(partPath, "utf-8")
				const part = JSON.parse(content) as StoredToolPart

				if (part.type === "tool" && part.state?.output && !part.truncated) {
					results.push({
						partPath,
						partId: part.id,
						messageID,
						toolName: part.tool,
						outputSize: part.state.output.length,
					})
				}
			} catch {
				continue
			}
		}
	}

	return results.sort((a, b) => b.outputSize - a.outputSize)
}

export function findLargestToolResult(sessionID: string): ToolResultInfo | null {
	const results = findToolResultsBySize(sessionID)
	return results.length > 0 ? results[0] : null
}

export function truncateToolResult(partPath: string): {
	success: boolean
	toolName?: string
	originalSize?: number
} {
	if (isSqliteBackend()) {
		if (!hasLoggedTruncateWarning) {
			log("[context-window-recovery] Disabled on SQLite backend: truncateToolResult")
			hasLoggedTruncateWarning = true
		}
		return { success: false }
	}

	try {
		const content = readFileSync(partPath, "utf-8")
		const part = JSON.parse(content) as StoredToolPart

		if (!part.state?.output) {
			return { success: false }
		}

		const originalSize = part.state.output.length
		const toolName = part.tool

		part.truncated = true
		part.originalSize = originalSize
		part.state.output = TRUNCATION_MESSAGE

		if (!part.state.time) {
			part.state.time = { start: Date.now() }
		}
		part.state.time.compacted = Date.now()

		writeFileSync(partPath, JSON.stringify(part, null, 2))

		return { success: true, toolName, originalSize }
	} catch {
		return { success: false }
	}
}

export function getTotalToolOutputSize(sessionID: string): number {
	const results = findToolResultsBySize(sessionID)
	return results.reduce((sum, result) => sum + result.outputSize, 0)
}

export function countTruncatedResults(sessionID: string): number {
	const messageIds = getMessageIds(sessionID)
	let count = 0

	for (const messageID of messageIds) {
		const partDir = join(PART_STORAGE_DIR, messageID)
		if (!existsSync(partDir)) continue

		for (const file of readdirSync(partDir)) {
			if (!file.endsWith(".json")) continue
			try {
				const content = readFileSync(join(partDir, file), "utf-8")
				const part = JSON.parse(content)
				if (part.truncated === true) {
					count++
				}
			} catch {
				continue
			}
		}
	}

	return count
}
