/**
 * Native Session Store - UI-side session management for Binary-Free Mode
 * 
 * This store provides a drop-in replacement for OpenCode SDK session operations
 * when running in Binary-Free (Lite) Mode.
 */

import { createSignal, createMemo, batch } from "solid-js"
import type { Session } from "../types/session"
import type { Message } from "../types/message"
import { nativeSessionApi, isLiteMode } from "../lib/lite-mode"
import type { NativeSession, NativeMessage } from "../lib/lite-mode"
import { getLogger } from "../lib/logger"

const log = getLogger("native-sessions")

// State
const [nativeSessions, setNativeSessions] = createSignal<Map<string, Map<string, Session>>>(new Map())
const [nativeMessages, setNativeMessages] = createSignal<Map<string, Message[]>>(new Map())
const [isLiteModeActive, setIsLiteModeActive] = createSignal<boolean | null>(null)

/**
 * Check and cache lite mode status
 */
export async function checkLiteMode(): Promise<boolean> {
    if (isLiteModeActive() !== null) {
        return isLiteModeActive()!
    }

    try {
        const liteMode = await isLiteMode()
        setIsLiteModeActive(liteMode)
        log.info(`Running in ${liteMode ? 'Lite' : 'Full'} mode`)
        return liteMode
    } catch (error) {
        log.warn("Failed to check lite mode, defaulting to full mode", error)
        setIsLiteModeActive(false)
        return false
    }
}

/**
 * Get the current lite mode status (synchronous, may be null if not checked)
 */
export function getLiteModeStatus(): boolean | null {
    return isLiteModeActive()
}

/**
 * Force set lite mode (for testing or manual override)
 */
export function forceLiteMode(enabled: boolean): void {
    setIsLiteModeActive(enabled)
}

// Convert native session to UI session format
function nativeToUiSession(native: NativeSession, workspaceId?: string): Session {
    return {
        id: native.id,
        instanceId: workspaceId || native.workspaceId,
        title: native.title || "",
        parentId: native.parentId ?? null,
        agent: native.agent || "Assistant",
        model: native.model ? {
            providerId: native.model.providerId,
            modelId: native.model.modelId,
        } : { providerId: "", modelId: "" },
        version: "0",
        time: {
            created: native.createdAt,
            updated: native.updatedAt
        },
        skills: []
    }
}

// Convert native message to UI message format
function nativeToUiMessage(native: NativeMessage): Message {
    const parts: any[] = []

    if (native.content) {
        parts.push({
            type: "text",
            text: native.content,
        })
    }

    return {
        id: native.id,
        sessionId: native.sessionId,
        type: native.role === "user" ? "user" : "assistant",
        parts,
        timestamp: native.createdAt,
        status: native.status === "completed" ? "complete" : "streaming",
        version: 0
    }
}


/**
 * Fetch sessions from native API
 */
export async function fetchNativeSessions(workspaceId: string): Promise<Session[]> {
    try {
        const sessions = await nativeSessionApi.listSessions(workspaceId)
        const uiSessions = sessions.map(s => nativeToUiSession(s, workspaceId))

        // Update state
        setNativeSessions(prev => {
            const next = new Map(prev)
            const wsMap = new Map<string, Session>()
            for (const s of uiSessions) {
                wsMap.set(s.id, s)
            }
            next.set(workspaceId, wsMap)
            return next
        })

        return uiSessions
    } catch (error) {
        log.error("Failed to fetch native sessions", error)
        return []
    }
}

/**
 * Create a new native session
 */
export async function createNativeSession(
    workspaceId: string,
    options?: {
        title?: string
        parentId?: string
        model?: { providerId: string; modelId: string }
        agent?: string
    }
): Promise<Session> {
    const native = await nativeSessionApi.createSession(workspaceId, options)
    const session = nativeToUiSession(native)

    // Update state
    setNativeSessions(prev => {
        const next = new Map(prev)
        const wsMap = new Map(next.get(workspaceId) ?? new Map())
        wsMap.set(session.id, session)
        next.set(workspaceId, wsMap)
        return next
    })

    return session
}

/**
 * Delete a native session
 */
export async function deleteNativeSession(workspaceId: string, sessionId: string): Promise<void> {
    await nativeSessionApi.deleteSession(workspaceId, sessionId)

    // Update state
    setNativeSessions(prev => {
        const next = new Map(prev)
        const wsMap = new Map(next.get(workspaceId) ?? new Map())
        wsMap.delete(sessionId)
        next.set(workspaceId, wsMap)
        return next
    })

    // Clear messages
    setNativeMessages(prev => {
        const next = new Map(prev)
        next.delete(`${workspaceId}:${sessionId}`)
        return next
    })
}

/**
 * Get messages for a native session
 */
export async function fetchNativeMessages(workspaceId: string, sessionId: string): Promise<Message[]> {
    try {
        const messages = await nativeSessionApi.getMessages(workspaceId, sessionId)
        const uiMessages = messages.map(nativeToUiMessage)

        // Update state
        const key = `${workspaceId}:${sessionId}`
        setNativeMessages(prev => {
            const next = new Map(prev)
            next.set(key, uiMessages)
            return next
        })

        return uiMessages
    } catch (error) {
        log.error("Failed to fetch native messages", error)
        return []
    }
}

/**
 * Get cached native sessions for a workspace
 */
export function getNativeSessions(workspaceId: string): Session[] {
    const wsMap = nativeSessions().get(workspaceId)
    return wsMap ? Array.from(wsMap.values()) : []
}

/**
 * Get cached native messages for a session
 */
export function getNativeMessages(workspaceId: string, sessionId: string): Message[] {
    const key = `${workspaceId}:${sessionId}`
    return nativeMessages().get(key) ?? []
}

/**
 * Send a message to a native session with streaming
 */
export async function sendNativeMessage(
    workspaceId: string,
    sessionId: string,
    content: string,
    options?: {
        provider?: "qwen" | "zai" | "zen"
        accessToken?: string
        resourceUrl?: string
        enableTools?: boolean
        onChunk?: (content: string) => void
        onDone?: () => void
        onError?: (error: string) => void
    }
): Promise<void> {
    const { provider = "zen", accessToken, resourceUrl, enableTools = true, onChunk, onDone, onError } = options ?? {}

    try {
        // Add user message to local state immediately
        const userMessage: Message = {
            id: `temp-${Date.now()}`,
            sessionId,
            type: "user",
            timestamp: Date.now(),
            parts: [{ type: "text", text: content } as any],
            status: "complete",
            version: 0
        }

        const key = `${workspaceId}:${sessionId}`
        setNativeMessages(prev => {
            const next = new Map(prev)
            const messages = [...(next.get(key) ?? []), userMessage]
            next.set(key, messages)
            return next
        })

        // Start streaming
        let fullContent = ""

        for await (const chunk of nativeSessionApi.streamPrompt(workspaceId, sessionId, content, {
            provider,
            accessToken,
            resourceUrl,
            enableTools,
        })) {
            if (chunk.type === "content" && chunk.data) {
                fullContent += chunk.data
                onChunk?.(chunk.data)
            } else if (chunk.type === "error") {
                onError?.(chunk.data ?? "Unknown error")
                return
            } else if (chunk.type === "done") {
                break
            }
        }

        // Add assistant message to local state
        const assistantMessage: Message = {
            id: `msg-${Date.now()}`,
            sessionId,
            type: "assistant",
            timestamp: Date.now(),
            parts: [{ type: "text", text: fullContent } as any],
            status: "complete",
            version: 0
        }

        setNativeMessages(prev => {
            const next = new Map(prev)
            const messages = [...(next.get(key) ?? []), assistantMessage]
            next.set(key, messages)
            return next
        })

        onDone?.()

        // Refresh messages from server to get the real IDs
        await fetchNativeMessages(workspaceId, sessionId)

    } catch (error) {
        log.error("Failed to send native message", error)
        onError?.(String(error))
    }
}

/**
 * Update a native session
 */
export async function updateNativeSession(
    workspaceId: string,
    sessionId: string,
    updates: { title?: string }
): Promise<Session | null> {
    const result = await nativeSessionApi.updateSession(workspaceId, sessionId, updates)
    if (!result) return null

    const session = nativeToUiSession(result)

    // Update state
    setNativeSessions(prev => {
        const next = new Map(prev)
        const wsMap = new Map(next.get(workspaceId) ?? new Map())
        wsMap.set(session.id, session)
        next.set(workspaceId, wsMap)
        return next
    })

    return session
}

export {
    nativeSessions,
    nativeMessages,
    isLiteModeActive,
}
