/**
 * SDK Session Sync - Reads sessions from OpenCode's storage and syncs to Native mode
 * 
 * OpenCode stores sessions in:
 * - Windows: %USERPROFILE%\.local\share\opencode\storage\session\{projectId}\
 * - Linux/Mac: ~/.local/share/opencode/storage/session/{projectId}/
 * 
 * The projectId is a hash of the workspace folder path.
 */

import { FastifyInstance } from "fastify"
import { readdir, readFile, appendFile } from "fs/promises"
import { existsSync } from "fs"
import { join } from "path"
import { homedir } from "os"
import { Logger } from "../../logger"
import { getSessionManager } from "../../storage/session-store"

interface SdkSyncRouteDeps {
    logger: Logger
    dataDir: string
}

interface OpenCodeSession {
    id: string
    version: string
    projectID: string
    directory: string
    title: string
    parentID?: string
    time: {
        created: number
        updated: number
    }
    summary?: {
        additions: number
        deletions: number
        files: number
    }
    share?: {
        url: string
        version: number
    }
    revert?: {
        messageID: string
        reason?: string
    }
}

/**
 * Get the OpenCode storage directory
 */
function getOpenCodeStorageDir(): string {
    const homeDir = homedir()

    // Windows: %USERPROFILE%\.local\share\opencode
    // Linux/Mac: ~/.local/share/opencode
    return join(homeDir, ".local", "share", "opencode", "storage")
}



/**
 * Read all sessions for a project from OpenCode's storage
 */
async function readOpenCodeSessions(folderPath: string, logger: Logger): Promise<OpenCodeSession[]> {
    const storageDir = getOpenCodeStorageDir()
    const sessionBaseDir = join(storageDir, "session")
    const debugLogPath = join(process.cwd(), "sdk-sync-debug.log")

    const logDebug = async (msg: string, obj?: any) => {
        const line = `[${new Date().toISOString()}] ${msg}${obj ? ' ' + JSON.stringify(obj) : ''}\n`
        await appendFile(debugLogPath, line).catch(() => { })
        logger.info(obj || {}, msg)
    }

    // Normalize target folder path for comparison
    const targetPath = folderPath.replace(/\\/g, '/').toLowerCase().trim()

    await logDebug("Starting SDK session search", { folderPath, targetPath, sessionBaseDir })

    if (!existsSync(sessionBaseDir)) {
        await logDebug("OpenCode session base directory not found", { sessionBaseDir })
        return []
    }

    try {
        const projectDirs = await readdir(sessionBaseDir, { withFileTypes: true })
        const dirs = projectDirs.filter(d => d.isDirectory()).map(d => d.name)

        await logDebug("Scanning project directories", { count: dirs.length })

        for (const projectId of dirs) {
            const sessionDir = join(sessionBaseDir, projectId)

            try {
                const files = await readdir(sessionDir)
                const firstSessionFile = files.find(f => f.startsWith("ses_") && f.endsWith(".json"))

                if (firstSessionFile) {
                    const content = await readFile(join(sessionDir, firstSessionFile), "utf-8")
                    const sessionData = JSON.parse(content) as OpenCodeSession

                    if (!sessionData.directory) {
                        await logDebug("Session file missing directory field", { projectId, firstSessionFile })
                        continue
                    }

                    const sessionPath = sessionData.directory.replace(/\\/g, '/').toLowerCase().trim()

                    if (sessionPath === targetPath) {
                        await logDebug("MATCH FOUND!", { projectId, sessionPath })

                        // This is the correct directory, read all sessions
                        const sessions: OpenCodeSession[] = [sessionData]
                        const otherFiles = files.filter(f => f !== firstSessionFile && f.startsWith("ses_") && f.endsWith(".json"))

                        for (const file of otherFiles) {
                            try {
                                const fileContent = await readFile(join(sessionDir, file), "utf-8")
                                sessions.push(JSON.parse(fileContent) as OpenCodeSession)
                            } catch (e) {
                                logger.warn({ file, error: e }, "Failed to read session file")
                            }
                        }

                        await logDebug("Read sessions count", { count: sessions.length })
                        return sessions
                    } else {
                        // Just log a few mismatches to avoid bloating
                        // await logDebug("Mismatch", { sessionPath, targetPath })
                    }
                }
            } catch (e) {
                await logDebug("Error scanning project directory", { projectId, error: String(e) })
            }
        }
    } catch (error) {
        await logDebug("Failed to scan OpenCode sessions directory", { error: String(error) })
    }

    await logDebug("No sessions found after scan")
    return []
}


export function registerSdkSyncRoutes(app: FastifyInstance, deps: SdkSyncRouteDeps) {
    const logger = deps.logger.child({ component: "sdk-sync" })
    const sessionManager = getSessionManager(deps.dataDir)

    /**
     * Sync sessions from SDK (OpenCode) to Native mode
     * This reads sessions directly from OpenCode's storage directory
     */
    app.post<{
        Params: { workspaceId: string }
        Body: { folderPath: string }
    }>("/api/native/workspaces/:workspaceId/sync-sdk", async (request, reply) => {
        const { workspaceId } = request.params
        const { folderPath } = request.body

        if (!folderPath) {
            return reply.status(400).send({ error: "Missing folderPath" })
        }

        logger.info({ workspaceId, folderPath }, "Starting SDK session sync")

        try {
            // Read sessions from OpenCode's storage
            const sdkSessions = await readOpenCodeSessions(folderPath, logger)

            if (sdkSessions.length === 0) {
                return {
                    success: true,
                    imported: 0,
                    skipped: 0,
                    message: "No SDK sessions found for this folder"
                }
            }

            // Convert OpenCode sessions to our format
            const sessionsToImport = sdkSessions.map(s => ({
                id: s.id,
                title: s.title,
                parentId: s.parentID || null,
                createdAt: s.time.created,
                updatedAt: s.time.updated,
                // We don't have model/agent info in the SDK session format
                // Those are stored in OpenCode's config, not session
            }))

            // Import to native session store
            const result = await sessionManager.importSessions(workspaceId, sessionsToImport)

            logger.info({ workspaceId, ...result }, "SDK session sync completed")

            return {
                success: true,
                imported: result.imported,
                skipped: result.skipped,
                total: sdkSessions.length
            }
        } catch (error) {
            logger.error({ error }, "SDK session sync failed")
            return reply.status(500).send({
                error: "Failed to sync SDK sessions",
                details: error instanceof Error ? error.message : String(error)
            })
        }
    })

    /**
     * Check if OpenCode sessions exist for a folder
     */
    app.post<{
        Body: { folderPath: string }
    }>("/api/native/check-sdk-sessions", async (request, reply) => {
        const { folderPath } = request.body

        if (!folderPath) {
            return reply.status(400).send({ error: "Missing folderPath" })
        }

        try {
            const sdkSessions = await readOpenCodeSessions(folderPath, logger)

            return {
                found: sdkSessions.length > 0,
                count: sdkSessions.length,
                sessions: sdkSessions.map(s => ({
                    id: s.id,
                    title: s.title,
                    created: s.time.created
                }))
            }
        } catch (error) {
            logger.error({ error }, "Failed to check SDK sessions")
            return { found: false, count: 0, sessions: [] }
        }
    })

    logger.info("SDK sync routes registered")
}
