package agent

import (
	"crypto/sha256"
	"encoding/hex"
	"strings"
)

const (
	openCodeSessionStorageErrorCode = "opencode_session_storage_error"
	openCodeSessionDatabaseBusyCode = "opencode_session_database_busy"
)

func classifyUserFacingRuntimeError(runtimeName, detail string) (string, bool) {
	code := classifyUserFacingRuntimeErrorCode(runtimeName, detail)
	if code == "" {
		return "", false
	}
	return openCodeSessionStorageFailureDetail(code), true
}

func classifyUserFacingRuntimeErrorCode(runtimeName, detail string) string {
	detail = strings.TrimSpace(detail)
	if detail == "" {
		return ""
	}
	runtimeName = strings.ToLower(strings.TrimSpace(runtimeName))
	lowerDetail := strings.ToLower(detail)
	if !strings.Contains(runtimeName, "opencode") {
		return ""
	}
	switch {
	case isOpenCodeSessionDatabaseBusy(lowerDetail):
		return openCodeSessionDatabaseBusyCode
	case isOpenCodeSessionStorageFailure(lowerDetail):
		return openCodeSessionStorageErrorCode
	default:
		return ""
	}
}

func isOpenCodeSessionStorageFailure(lowerDetail string) bool {
	if !strings.Contains(lowerDetail, "failed query:") {
		return false
	}
	return strings.Contains(lowerDetail, `insert into "part"`) ||
		strings.Contains(lowerDetail, "insert into part") ||
		(strings.Contains(lowerDetail, "service=session.processor") &&
			strings.Contains(lowerDetail, "part"))
}

func isOpenCodeSessionDatabaseBusy(lowerDetail string) bool {
	return strings.Contains(lowerDetail, "database is locked") ||
		strings.Contains(lowerDetail, "sqlite_busy") ||
		strings.Contains(lowerDetail, "sqlite busy")
}

func openCodeSessionStorageFailureDetail(code string) string {
	return "OpenCode runtime failed while writing local session data, so the current reply was not completed. Restart this agent or retry later. AgentTeam kept the raw runtime diagnostics. (code: " + code + ")"
}

func runtimeErrorDiagnosticFingerprint(detail string) (int, string) {
	detail = strings.TrimSpace(detail)
	if detail == "" {
		return 0, ""
	}
	sum := sha256.Sum256([]byte(detail))
	return len(detail), hex.EncodeToString(sum[:8])
}
