/**
 * Lite Mode API Client - Binary-Free Mode
 * 
 * This provides a client for working with NomadArch in Binary-Free Mode,
 * using native session management instead of the OpenCode binary.
 */

import { CODENOMAD_API_BASE } from "./api-client"
import { getLogger } from "./logger"

const log = getLogger("lite-mode")

export interface ModeInfo {
    mode: "lite" | "full"
    binaryFreeMode: boolean
    nativeSessions: boolean
    opencodeBinaryAvailable: boolean
    providers: {
        qwen: boolean
        zai: boolean
        zen: boolean
    }
}

export interface NativeSession {
    id: string
    workspaceId: string
    title?: string
    parentId?: string | null
    createdAt: number
    updatedAt: number
    messageIds: string[]
    model?: {
        providerId: string
        modelId: string
    }
    agent?: string
}

export interface NativeMessage {
    id: string
    sessionId: string
    role: "user" | "assistant" | "system" | "tool"
    content?: string
    createdAt: number
    updatedAt: number
    status?: "pending" | "streaming" | "completed" | "error"
}

let modeCache: ModeInfo | null = null

/**
 * Get the current running mode (lite or full)
 */
export async function getMode(): Promise<ModeInfo> {
    if (modeCache) return modeCache

    try {
        const response = await fetch(`${CODENOMAD_API_BASE}/api/meta/mode`)
        if (!response.ok) {
            throw new Error(`Failed to fetch mode: ${response.status}`)
        }
        modeCache = await response.json()
        log.info(`Running in ${modeCache?.mode} mode`, { binaryFree: modeCache?.binaryFreeMode })
        return modeCache!
    } catch (error) {
        log.warn("Failed to fetch mode, assuming lite mode", error)
        // Default to lite mode if we can't determine
        return {
            mode: "lite",
            binaryFreeMode: true,
            nativeSessions: true,
            opencodeBinaryAvailable: false,
            providers: { qwen: true, zai: true, zen: true }
        }
    }
}

/**
 * Check if running in Binary-Free (lite) mode
 */
export async function isLiteMode(): Promise<boolean> {
    const mode = await getMode()
    return mode.binaryFreeMode
}

/**
 * Native Session API for Binary-Free Mode
 */
export const nativeSessionApi = {
    async listSessions(workspaceId: string): Promise<NativeSession[]> {
        const response = await fetch(`${CODENOMAD_API_BASE}/api/native/workspaces/${encodeURIComponent(workspaceId)}/sessions`)
        if (!response.ok) throw new Error("Failed to list sessions")
        const data = await response.json()
        return data.sessions
    },

    async createSession(workspaceId: string, options?: {
        title?: string
        parentId?: string
        model?: { providerId: string; modelId: string }
        agent?: string
    }): Promise<NativeSession> {
        const response = await fetch(`${CODENOMAD_API_BASE}/api/native/workspaces/${encodeURIComponent(workspaceId)}/sessions`, {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify(options ?? {})
        })
        if (!response.ok) throw new Error("Failed to create session")
        const data = await response.json()
        return data.session
    },

    async getSession(workspaceId: string, sessionId: string): Promise<NativeSession | null> {
        const response = await fetch(`${CODENOMAD_API_BASE}/api/native/workspaces/${encodeURIComponent(workspaceId)}/sessions/${encodeURIComponent(sessionId)}`)
        if (response.status === 404) return null
        if (!response.ok) throw new Error("Failed to get session")
        const data = await response.json()
        return data.session
    },

    async updateSession(workspaceId: string, sessionId: string, updates: Partial<NativeSession>): Promise<NativeSession | null> {
        const response = await fetch(`${CODENOMAD_API_BASE}/api/native/workspaces/${encodeURIComponent(workspaceId)}/sessions/${encodeURIComponent(sessionId)}`, {
            method: "PATCH",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify(updates)
        })
        if (response.status === 404) return null
        if (!response.ok) throw new Error("Failed to update session")
        const data = await response.json()
        return data.session
    },

    async deleteSession(workspaceId: string, sessionId: string): Promise<boolean> {
        const response = await fetch(`${CODENOMAD_API_BASE}/api/native/workspaces/${encodeURIComponent(workspaceId)}/sessions/${encodeURIComponent(sessionId)}`, {
            method: "DELETE"
        })
        return response.ok || response.status === 204
    },

    async forkSession(workspaceId: string, sessionId: string): Promise<NativeSession> {
        const response = await fetch(`${CODENOMAD_API_BASE}/api/native/workspaces/${encodeURIComponent(workspaceId)}/sessions/${encodeURIComponent(sessionId)}/fork`, {
            method: "POST"
        })
        if (!response.ok) throw new Error("Failed to fork session")
        const data = await response.json()
        return data.session
    },

    async revertSession(workspaceId: string, sessionId: string, messageId?: string): Promise<NativeSession> {
        const response = await fetch(`${CODENOMAD_API_BASE}/api/native/workspaces/${encodeURIComponent(workspaceId)}/sessions/${encodeURIComponent(sessionId)}/revert`, {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify({ messageId })
        })
        if (!response.ok) throw new Error("Failed to revert session")
        const data = await response.json()
        return data.session
    },

    async getMessages(workspaceId: string, sessionId: string): Promise<NativeMessage[]> {
        const response = await fetch(`${CODENOMAD_API_BASE}/api/native/workspaces/${encodeURIComponent(workspaceId)}/sessions/${encodeURIComponent(sessionId)}/messages`)
        if (!response.ok) throw new Error("Failed to get messages")
        const data = await response.json()
        return data.messages
    },

    async appendMessages(
        workspaceId: string,
        sessionId: string,
        messages: Array<{
            id?: string
            role: "user" | "assistant" | "system" | "tool"
            content?: string
            createdAt?: number
            updatedAt?: number
            status?: "pending" | "streaming" | "completed" | "error"
        }>
    ): Promise<NativeMessage[]> {
        const response = await fetch(`${CODENOMAD_API_BASE}/api/native/workspaces/${encodeURIComponent(workspaceId)}/sessions/${encodeURIComponent(sessionId)}/messages`, {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify({ messages })
        })
        if (!response.ok) throw new Error("Failed to append messages")
        const data = await response.json()
        return data.messages
    },

    /**
     * Import sessions from SDK mode to Native mode
     */
    async importSessions(workspaceId: string, sessions: Array<{
        id: string
        title?: string
        parentId?: string | null
        createdAt?: number
        updatedAt?: number
        model?: { providerId: string; modelId: string }
        agent?: string
        messages?: Array<{
            id: string
            role: "user" | "assistant" | "system" | "tool"
            content?: string
            createdAt?: number
        }>
    }>): Promise<{ success: boolean; imported: number; skipped: number }> {
        const response = await fetch(`${CODENOMAD_API_BASE}/api/native/workspaces/${encodeURIComponent(workspaceId)}/sessions/import`, {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify({ sessions })
        })
        if (!response.ok) throw new Error("Failed to import sessions")
        return response.json()
    },

    /**
     * Sync sessions from SDK (OpenCode) to Native mode
     * This reads sessions directly from OpenCode's storage
     */
    async syncFromSdk(workspaceId: string, folderPath: string): Promise<{
        success: boolean
        imported: number
        skipped: number
        total?: number
        message?: string
    }> {
        const response = await fetch(`${CODENOMAD_API_BASE}/api/native/workspaces/${encodeURIComponent(workspaceId)}/sync-sdk`, {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify({ folderPath })
        })
        if (!response.ok) throw new Error("Failed to sync SDK sessions")
        return response.json()
    },

    /**
     * Check if SDK sessions exist for a folder
     */
    async checkSdkSessions(folderPath: string): Promise<{
        found: boolean
        count: number
        sessions: Array<{ id: string; title: string; created: number }>
    }> {
        const response = await fetch(`${CODENOMAD_API_BASE}/api/native/check-sdk-sessions`, {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify({ folderPath })
        })
        if (!response.ok) throw new Error("Failed to check SDK sessions")
        return response.json()
    },


    /**
     * Send a prompt to the session and get a streaming response
     */
    async* streamPrompt(
        workspaceId: string,
        sessionId: string,
        content: string,
        options?: {
            provider?: "qwen" | "zai" | "zen"
            accessToken?: string
            resourceUrl?: string
            enableTools?: boolean
        }
    ): AsyncGenerator<{ type: "content" | "done" | "error"; data?: string }> {
        const response = await fetch(`${CODENOMAD_API_BASE}/api/native/workspaces/${encodeURIComponent(workspaceId)}/sessions/${encodeURIComponent(sessionId)}/prompt`, {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify({
                content,
                provider: options?.provider ?? "qwen",
                accessToken: options?.accessToken,
                resourceUrl: options?.resourceUrl,
                enableTools: options?.enableTools ?? true
            })
        })

        if (!response.ok) {
            yield { type: "error", data: `Request failed: ${response.status}` }
            return
        }

        const reader = response.body?.getReader()
        if (!reader) {
            yield { type: "error", data: "No response body" }
            return
        }

        const decoder = new TextDecoder()
        let buffer = ""

        while (true) {
            const { done, value } = await reader.read()
            if (done) break

            buffer += decoder.decode(value, { stream: true })
            const lines = buffer.split("\n")
            buffer = lines.pop() ?? ""

            for (const line of lines) {
                if (!line.trim()) continue
                if (line.startsWith("data: ")) {
                    const data = line.slice(6)
                    if (data === "[DONE]") {
                        yield { type: "done" }
                        return
                    }
                    try {
                        const parsed = JSON.parse(data)
                        if (parsed.error) {
                            yield { type: "error", data: parsed.error }
                        } else if (parsed.choices?.[0]?.delta?.content) {
                            yield { type: "content", data: parsed.choices[0].delta.content }
                        }
                    } catch {
                        // Skip invalid JSON
                    }
                }
            }
        }

        yield { type: "done" }
    }
}

/**
 * Clear mode cache (for testing or after config changes)
 */
export function clearModeCache(): void {
    modeCache = null
}
