import 'dotenv/config'
import { electronApp, optimizer, is } from '@electron-toolkit/utils'
import { app, shell, BrowserWindow, ipcMain } from 'electron'
import filesystemPlugin from '@takerofnotes/plugin-filesystem'
import supabasePlugin from '@takerofnotes/plugin-supabase'
import PluginRegistry from './core/PluginRegistry.js'
import Config from './core/Config.js'
import { join } from 'path'

const preloadPath = join(__dirname, '../preload/index.mjs')
const rendererPath = join(__dirname, '../renderer/index.html')

// Main window
function createWindow() {
    const mainWindow = new BrowserWindow({
        width: 354,
        height: 549,
        show: false,
        autoHideMenuBar: true,
        webPreferences: {
            preload: preloadPath,
            sandbox: false,
        },
    })

    mainWindow.on('ready-to-show', () => {
        mainWindow.show()
    })

    mainWindow.webContents.setWindowOpenHandler((details) => {
        shell.openExternal(details.url)
        return { action: 'deny' }
    })

    if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
        mainWindow.loadURL(process.env['ELECTRON_RENDERER_URL'])
    } else {
        mainWindow.loadFile(rendererPath)
    }
}

// Open note in new window
function createNoteWindow(noteId) {
    const noteWindow = new BrowserWindow({
        width: 354,
        height: 549,
        autoHideMenuBar: true,
        webPreferences: {
            preload: preloadPath,
            contextIsolation: true,
            nodeIntegration: false,
            sandbox: false,
        },
    })

    if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
        noteWindow.loadURL(
            `${process.env['ELECTRON_RENDERER_URL']}/#/note/${noteId}`,
        )
    } else {
        noteWindow.loadFile(rendererPath, {
            hash: `/note/${noteId}`,
        })
    }
}

app.whenReady().then(async () => {
    // Open note in new window
    ipcMain.on('open-note-window', (_, noteId) => {
        createNoteWindow(noteId)
    })

    // Broadcast note changes to all windows
    const broadcastNoteChange = (event, data) => {
        BrowserWindow.getAllWindows().forEach((win) => {
            win.webContents.send(event, data)
        })
    }

    // Create plugin registry
    const registry = new PluginRegistry()

    // Register built-in plugins
    registry.register(filesystemPlugin)
    registry.register(supabasePlugin)

    // Pull plugin config
    const config = new Config(filesystemPlugin)
    const initialConfig = await config.load()

    const setActivePlugin = async (pluginId) => {
        const currentConfig = await config.load()
        await config.write({ ...currentConfig, activeAdapter: pluginId })

        const plugin = registry.get(pluginId)
        const adapterConfig = currentConfig.adapters[pluginId] || {}
        const adapter = plugin.createAdapter(adapterConfig)

        // Initialize adapter
        await adapter.init()

        // Handle adapter methods via IPC
        ipcMain.removeHandler('adapter:call')
        ipcMain.handle('adapter:call', async (_, method, args) => {
            if (!adapter[method]) {
                throw new Error(`Invalid adapter method: ${method}`)
            }

            return await adapter[method](...args)
        })

        broadcastNoteChange('plugin-changed', pluginId)

        return true
    }

    // Set active plugin
    await setActivePlugin(initialConfig.activeAdapter)

    // Get/set config
    ipcMain.handle('getConfig', async () => {
        return await config.load()
    })
    ipcMain.handle('setConfig', async (_, newConfig) => {
        await config.write(newConfig)
    })

    // Get/set plugins
    ipcMain.handle('listPlugins', async () => {
        return registry.list()
    })
    ipcMain.handle('setActivePlugin', async (_, pluginId) => {
        return await setActivePlugin(pluginId)
    })

    // Handle note change events from renderer
    ipcMain.on('note-changed', (_, event, data) => {
        broadcastNoteChange(event, data)
    })

    electronApp.setAppUserModelId('com.electron')

    app.on('browser-window-created', (_, window) => {
        optimizer.watchWindowShortcuts(window)
    })

    createWindow()

    app.on('activate', function () {
        if (BrowserWindow.getAllWindows().length === 0) createWindow()
    })
})

app.on('window-all-closed', () => {
    if (process.platform !== 'darwin') {
        app.quit()
    }
})
