import { ipcMain, app, dialog, shell } from 'electron'
import fs from 'fs'
import { processManager } from '../services/ProcessManager'
import { configService } from '../services/ConfigService'
import { downloadService } from '../services/DownloadService'
import { projectService } from '../services/ProjectService'
import { phpManagerService } from '../services/PhpManagerService'
import { mariaDbManagerService } from '../services/MariaDbManagerService'
import { nginxManagerService } from '../services/NginxManagerService'
import { apacheManagerService } from '../services/ApacheManagerService'
import { phpMyAdminService } from '../services/PhpMyAdminService'
import { portMappingService } from '../services/PortMappingService'
import path from 'path'
import { mariaDbOperationService } from '../services/MariaDbOperationService'
import { cliAliasService } from '../services/CliAliasService'

function findExecutable(dir: string, name: string): string | null {
    if (!fs.existsSync(dir)) return null
    const files = fs.readdirSync(dir)
    for (const file of files) {
        const fullPath = path.join(dir, file)
        const stat = fs.statSync(fullPath)
        if (stat.isDirectory()) {
            const found = findExecutable(fullPath, name)
            if (found) return found
        } else if (file.toLowerCase() === name.toLowerCase()) {
            return fullPath
        }
    }
    return null
}

async function rebuildNginxConfig(forceProjects: boolean = false): Promise<{ binPath: string; nginxPrefix: string; configPath: string }> {
    const settings = configService.getSettings()
    const binDir = path.join(configService.getBasePath(), 'bin')
    const nginxDir = path.join(binDir, 'nginx')
    const nginxVersions = fs.readdirSync(nginxDir).filter(f => fs.statSync(path.join(nginxDir, f)).isDirectory())
    const activeVersion = nginxVersions[0]
    if (!activeVersion) throw new Error('Nginx sürümü bulunamadı.')

    const nginxPrefix = path.join(nginxDir, activeVersion)
    const isWindows = process.platform === 'win32';
    const binPath = path.join(nginxPrefix, isWindows ? 'nginx.exe' : 'nginx')
    const confDir = path.join(nginxPrefix, 'conf')
    const logDir = path.join(configService.getBasePath(), 'logs')
    const rootPath = path.join(configService.getBasePath(), 'www')
    if (!fs.existsSync(rootPath)) fs.mkdirSync(rootPath, { recursive: true })

    // Ensure directories exist
    const projectsConfDir = path.join(configService.getBasePath(), 'generated_configs', 'projects')
    if (!fs.existsSync(projectsConfDir)) fs.mkdirSync(projectsConfDir, { recursive: true })

    const tempDirs = ['temp', 'temp/client_body_temp', 'temp/proxy_temp', 'temp/fastcgi_temp', 'temp/uwsgi_temp', 'temp/scgi_temp', 'logs']
    for (const dir of tempDirs) {
        const fullDir = path.join(nginxPrefix, dir)
        if (!fs.existsSync(fullDir)) fs.mkdirSync(fullDir, { recursive: true })
    }

    // Generate project configs
    const allProjects = await projectService.getProjects()
    const projects = allProjects.filter(p => !p.serverType || p.serverType === 'nginx')
    for (const p of projects) {
        const projectConfPath = path.join(projectsConfDir, `${p.host}.conf`)
        let shouldGenerate = forceProjects || !fs.existsSync(projectConfPath)

        // If file exists, check if it was manually edited
        if (!shouldGenerate && fs.existsSync(projectConfPath)) {
            const currentContent = fs.readFileSync(projectConfPath, 'utf8')
            if (!currentContent.includes('# MANUAL_EDIT')) {
                // Overwrite old, broken configs that don't have the marker
                shouldGenerate = true
            }
        }

        if (shouldGenerate) {
            const phpPort = portMappingService.getPhpPort(p.phpVersion)
            // Ensure path ends with a slash for alias compatibility
            let normalizedPath = p.path.replace(/\\/g, '/')
            if (!normalizedPath.endsWith('/')) {
                normalizedPath += '/'
            }

            await configService.generateConfig('nginx_project.conf.template', `projects/${p.host}.conf`, {
                HOST: p.host,
                PATH: normalizedPath,
                PHP_PORT: phpPort.toString(),
                CONF_DIR: confDir.replace(/\\/g, '/')
            })
        }
    }

    const projectsInclusion = projects.length > 0
        ? `include "${projectsConfDir.replace(/\\/g, '/')}/*.conf";`
        : ''

    const configPath = await configService.generateConfig('nginx.conf.template', 'nginx.conf', {
        PORT: settings.nginxPort,
        LISTEN_ADDRESS: settings.allowRemoteAccess ? '0.0.0.0' : '127.0.0.1',
        PHP_PORT: settings.phpPort,
        ROOT: rootPath,
        LOG_DIR: logDir.replace(/\\/g, '/'),
        CONF_DIR: confDir.replace(/\\/g, '/'),
        PHPMYADMIN_DIR: phpMyAdminService.getPath().replace(/\\/g, '/'),
        PROJECTS: projectsInclusion
    })

    return { binPath, nginxPrefix, configPath }
}

async function restartNginx(): Promise<{ success: boolean; message: string }> {
    try {
        const { binPath, nginxPrefix, configPath } = await rebuildNginxConfig(false)

        // Force kill Nginx to ensure it picks up new config on Windows
        await processManager.forceKillAll('nginx')
        await processManager.stopService('nginx')
        // Give OS time to release the port
        await new Promise(resolve => setTimeout(resolve, 1000))

        // Start service
        const success = await processManager.startService('nginx', binPath, ['-p', nginxPrefix, '-c', configPath], false)

        if (success) {
            return { success: true, message: 'Nginx restart successful' }
        } else {
            const errorLogs = await processManager.getLastErrorLogs('nginx')
            return { success: false, message: `Nginx restart failed:\n${errorLogs.join('\n')}` }
        }
    } catch (error: any) {
        return { success: false, message: `Restart hatası: ${error.message}` }
    }
}
async function reloadNginx(): Promise<{ success: boolean; message: string }> {
    try {
        const { binPath, nginxPrefix, configPath } = await rebuildNginxConfig(false)
        const result = await processManager.runOnce(binPath, ['-p', nginxPrefix, '-c', configPath, '-s', 'reload'], 'nginx')
        if (result.success) {
            console.log('Nginx reload successful')
            return { success: true, message: 'Nginx reloaded' }
        } else {
            // Fallback to full restart if reload fails (common on Windows)
            return await restartNginx()
        }
    } catch (error: any) {
        return { success: false, message: `Reload hatası: ${error.message}` }
    }
}
async function rebuildApacheConfig(forceProjects: boolean = false): Promise<{ binPath: string; apacheDir: string; configPath: string }> {
    const settings = configService.getSettings()
    const binDir = path.join(configService.getBasePath(), 'bin')
    const apacheDir = path.join(binDir, 'apache')

    const isWindows = process.platform === 'win32';
    const binPath = findExecutable(apacheDir, isWindows ? 'httpd.exe' : 'httpd')
    if (!binPath) throw new Error('Apache executable bulunamadı.')

    const apacheRoot = path.dirname(path.dirname(binPath)) // bin'in üstü
    const logDir = path.join(configService.getBasePath(), 'logs')
    const rootPath = path.join(configService.getBasePath(), 'www')
    if (!fs.existsSync(rootPath)) fs.mkdirSync(rootPath, { recursive: true })

    // Ensure directories exist
    const projectsConfDir = path.join(configService.getBasePath(), 'generated_configs', 'projects_apache')
    if (!fs.existsSync(projectsConfDir)) fs.mkdirSync(projectsConfDir, { recursive: true })

    // Generate project configs
    const allProjects = await projectService.getProjects()
    const projects = allProjects.filter(p => p.serverType === 'apache')
    for (const p of projects) {
        const projectConfPath = path.join(projectsConfDir, `${p.host}.conf`)
        let shouldGenerate = forceProjects || !fs.existsSync(projectConfPath)

        if (shouldGenerate) {
            const phpPort = portMappingService.getPhpPort(p.phpVersion)
            let normalizedPath = p.path.replace(/\\/g, '/')
            if (!normalizedPath.endsWith('/')) normalizedPath += '/'

            await configService.generateConfig('apache_project.conf.template', `projects_apache/${p.host}.conf`, {
                HOST: p.host,
                PATH: normalizedPath,
                PHP_PORT: phpPort.toString()
            })
        }
    }

    const projectsInclusion = projects.length > 0
        ? `Include "${projectsConfDir.replace(/\\/g, '/')}/*.conf"`
        : ''

    const configPath = await configService.generateConfig('httpd.conf.template', 'httpd.conf', {
        PORT: settings.apachePort || '8080',
        LISTEN_ADDRESS: settings.allowRemoteAccess ? '0.0.0.0' : '127.0.0.1',
        PHP_PORT: settings.phpPort,
        ROOT: rootPath.replace(/\\/g, '/'),
        SRVROOT: apacheRoot.replace(/\\/g, '/'),
        LOG_DIR: logDir.replace(/\\/g, '/'),
        PHPMYADMIN_DIR: phpMyAdminService.getPath().replace(/\\/g, '/'),
        PROJECTS: projectsInclusion
    })

    return { binPath, apacheDir, configPath }
}

async function restartApache(): Promise<{ success: boolean; message: string }> {
    try {
        const { binPath, configPath } = await rebuildApacheConfig(false)

        await processManager.forceKillAll('apache')
        await processManager.stopService('apache')
        await new Promise(resolve => setTimeout(resolve, 1000))

        const success = await processManager.startService('apache', binPath, ['-f', configPath], false)

        if (success) {
            return { success: true, message: 'Apache restart successful' }
        } else {
            const errorLogs = await processManager.getLastErrorLogs('apache')
            return { success: false, message: `Apache restart failed:\n${errorLogs.join('\n')}` }
        }
    } catch (error: any) {
        return { success: false, message: `Restart hatası: ${error.message}` }
    }
}

export function registerIpcHandlers(): void {
    // Service management
    ipcMain.handle('services:reload', async (_event, serviceName: string) => {
        if (serviceName === 'nginx') return await reloadNginx()
        if (serviceName === 'apache') return await restartApache() // Apache doesn't have a simple reload here
        return { success: false, message: 'Bu servis için reload desteklenmiyor.' }
    })

    ipcMain.handle('services:start', async (_event, serviceName: string) => {
        try {
            const settings = configService.getSettings()
            const binDir = path.join(configService.getBasePath(), 'bin')

            if (serviceName === 'nginx') {
                const { binPath, nginxPrefix, configPath } = await rebuildNginxConfig(false)
                const success = await processManager.startService('nginx', binPath, ['-p', nginxPrefix, '-c', configPath], false)
                if (!success) {
                    const errorLogs = await processManager.getLastErrorLogs('nginx')
                    return { success: false, message: `Nginx başlatılamadı.\n\n${errorLogs.join('\n')}` }
                }
                return { success, message: success ? 'Nginx başlatıldı.' : 'Nginx devreye alınamadı.' }
            }

            if (serviceName === 'apache') {
                const { binPath, configPath } = await rebuildApacheConfig(false)
                const success = await processManager.startService('apache', binPath, ['-f', configPath], false)
                if (!success) {
                    const errorLogs = await processManager.getLastErrorLogs('apache')
                    return { success: false, message: `Apache başlatılamadı.\n\n${errorLogs.join('\n')}` }
                }
                return { success, message: success ? 'Apache başlatıldı.' : 'Apache devreye alınamadı.' }
            }

            if (serviceName.startsWith('php')) {
                const versionMatch = serviceName.match(/^php:(.+)$/)
                const phpVersion = versionMatch ? versionMatch[1] : null
                const phpId = phpVersion ? `php-${phpVersion}` : null

                const isWindows = process.platform === 'win32';
                const phpDir = phpId ? path.join(binDir, phpId) : binDir
                const phpBinary = isWindows ? 'php-cgi.exe' : 'php-cgi';
                const binPath = findExecutable(phpDir, phpBinary)

                if (!binPath) return { success: false, message: `${phpVersion || ''} PHP executable bulunamadı. Lütfen indirin.` }

                const phpPort = phpVersion ? portMappingService.getPhpPort(phpVersion) : settings.phpPort
                const extDir = path.join(path.dirname(binPath), 'ext').replace(/\\/g, '/')
                const gdExtName = fs.existsSync(path.join(extDir, 'php_gd2.dll')) ? 'gd2' : 'gd'

                const sessionDir = path.join(configService.getBasePath(), 'data', 'sessions').replace(/\\/g, '/')
                const tempDir = path.join(configService.getBasePath(), 'data', 'temp').replace(/\\/g, '/')

                if (!fs.existsSync(sessionDir)) fs.mkdirSync(sessionDir, { recursive: true })
                if (!fs.existsSync(tempDir)) fs.mkdirSync(tempDir, { recursive: true })

                const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms))

                // --- 1. Get extensions from local php.ini ---
                let extensionsList = ''
                let errorReporting = 'E_ALL'
                let displayErrors = 'On'

                const localIniPath = path.join(phpDir, 'php.ini')
                const mustHaves = ['curl', 'mbstring', 'openssl', 'mysqli', 'pdo_mysql', 'gd', 'fileinfo', 'exif', 'intl', 'bz2', 'gettext', 'soap', 'xsl']

                if (fs.existsSync(localIniPath)) {
                    const localIniContent = fs.readFileSync(localIniPath, 'utf8')

                    // 1. Get extensions
                    const extMatches = localIniContent.match(/^\s*extension\s*=.*$/gm)
                    if (extMatches) {
                        extensionsList = extMatches.join('\n')
                    }

                    // 2. Get error settings
                    const erMatch = localIniContent.match(/^\s*error_reporting\s*=\s*(.+)$/m)
                    if (erMatch) errorReporting = erMatch[1].trim()

                    const deMatch = localIniContent.match(/^\s*display_errors\s*=\s*(.+)$/m)
                    if (deMatch) displayErrors = deMatch[1].trim()
                } else {
                    // Fallback formatting based on version
                    const prefix = (phpVersion?.startsWith('5.') || phpVersion?.startsWith('7.')) ? 'php_' : ''
                    const suffix = (phpVersion?.startsWith('5.') || phpVersion?.startsWith('7.')) ? '.dll' : ''
                    extensionsList = mustHaves.map(m => `extension=${prefix}${m}${suffix}`).join('\n')
                }

                const configPath = await configService.generateConfig('php.ini.template', `php_${phpVersion || 'default'}.ini`, {
                    EXT_DIR: extDir,
                    GD_EXT: gdExtName,
                    SESSION_DIR: sessionDir,
                    TEMP_DIR: tempDir,
                    EXTENSIONS: extensionsList,
                    ERROR_REPORTING: errorReporting,
                    DISPLAY_ERRORS: displayErrors
                })

                // Add a small delay to ensure previous instance (if any) is fully killed
                await sleep(1000)
                const success = await processManager.startService(serviceName, binPath, ['-b', `127.0.0.1:${phpPort}`, '-c', configPath], false)

                if (!success) {
                    const errorLogs = await processManager.getLastErrorLogs(serviceName)
                    return { success: false, message: `${phpVersion || ''} PHP başlatılamadı.\n\n${errorLogs.join('\n')}` }
                }

                return { success, message: success ? `${phpVersion || ''} PHP başlatıldı.` : `${phpVersion || ''} PHP devreye alınamadı.` }
            }

            if (serviceName.startsWith('mariadb') || serviceName.startsWith('mysql')) {
                const versionMatch = serviceName.match(/^(?:mariadb|mysql):(.+)$/)
                const dbVersion = versionMatch ? versionMatch[1] : null
                const dbId = dbVersion ? `mariadb-${dbVersion}` : 'mariadb-default'

                const dataDir = path.join(configService.getBasePath(), 'data', dbId)
                const dbBinDir = dbVersion ? path.join(binDir, `mariadb-${dbVersion}`) : binDir

                const isWindows = process.platform === 'win32';
                const dbBinary = isWindows ? 'mariadbd.exe' : 'mariadbd';
                const installBinary = isWindows ? 'mariadb-install-db.exe' : 'mariadb-install-db';
                const mysqlInstallBinary = isWindows ? 'mysql_install_db.exe' : 'mysql_install_db';

                let binPath = findExecutable(dbBinDir, dbBinary) || findExecutable(dbBinDir, isWindows ? 'mysqld.exe' : 'mysqld');
                let installPath = findExecutable(dbBinDir, installBinary) || findExecutable(dbBinDir, mysqlInstallBinary);

                if (!binPath) return { success: false, message: 'MariaDB executable bulunamadı. Lütfen indirin.' }

                const dbVersions = await mariaDbManagerService.getVersions()
                const dbInfo = dbVersions.find(v => v.id === `mariadb-${dbVersion}`)
                const dbPort = dbInfo?.port || (dbVersion ? portMappingService.getMariaDbPort(dbVersion).toString() : settings.mariaDbPort)

                // Force kill this specific version if running or generic mysql
                await processManager.forceKillAll(serviceName)

                // Also kill anything else listening on the same port
                await processManager.killByPort(serviceName, dbPort)

                // Initialize if data directory is empty or missing system tables
                const systemDbDir = path.join(dataDir, 'mysql')
                if (!fs.existsSync(dataDir) || fs.readdirSync(dataDir).length === 0 || !fs.existsSync(systemDbDir)) {
                    if (!fs.existsSync(dataDir)) fs.mkdirSync(dataDir, { recursive: true })
                    console.log(`Initializing MariaDB data directory for ${serviceName}...`)

                    try {
                        const normalizedDataDir = dataDir.replace(/\\/g, '/')
                        if (installPath) {
                            console.log(`Using install tool: ${installPath}`)
                            // MariaDB specific installation
                            await processManager.runOnce(installPath, [
                                `--datadir=${normalizedDataDir}`
                            ])
                        } else {
                            console.log(`Using server init: ${binPath}`)
                            // MySQL 5.7+ / modern MariaDB fallback
                            await processManager.runOnce(binPath, ['--initialize-insecure', `--datadir=${normalizedDataDir}`])
                        }
                    } catch (err) {
                        console.log(`Initialization tool failed, trying template copy for ${serviceName}...`)
                        // Fallback: Copy default 'data' folder from binary dir if it exists
                        const templateDataDir = path.join(dbBinDir, 'data')
                        if (fs.existsSync(templateDataDir)) {
                            fs.cpSync(templateDataDir, dataDir, { recursive: true })
                            console.log(`Successfully copied template data for ${serviceName}`)
                        } else {
                            throw new Error(`MariaDB initialization failed and no template data found at ${templateDataDir}`)
                        }
                    }
                }

                const sanitizedServiceName = serviceName.replace(/:/g, '_')
                const logFile = path.join(configService.getBasePath(), 'logs', `${sanitizedServiceName}_error.log`)

                const configPath = await configService.generateConfig('mariadb.ini.template', `mariadb_${dbId || 'default'}.ini`, {
                    PORT: dbPort,
                    DATADIR: dataDir.replace(/\\/g, '/'),
                    SOCKET: `/tmp/${sanitizedServiceName}.sock`,
                    LOG_FILE: logFile.replace(/\\/g, '/')
                })

                const success = await processManager.startService(serviceName, binPath, ['--defaults-file=' + configPath], false)

                if (success) {
                    // Quick health check
                    await new Promise(r => setTimeout(r, 1500))
                    if (!processManager.isServiceRunning(serviceName)) {
                        const errorLogs = await processManager.getLastErrorLogs(serviceName)
                        return { success: false, message: `${dbVersion || ''} MariaDB başlatıldı ancak çalışma hatası verdi (ExitCode: 1).\n\n${errorLogs.length > 0 ? 'Önemli Hata Logları:\n' + errorLogs.join('\n') : 'Lütfen log sekmesini kontrol edin.'}` }
                    }
                } else {
                    const errorLogs = await processManager.getLastErrorLogs(serviceName)
                    return { success: false, message: `${dbVersion || ''} MariaDB başlatılamadı.\n\n${errorLogs.join('\n')}` }
                }

                return { success, message: success ? `${dbVersion || ''} MariaDB başlatıldı.` : `${dbVersion || ''} MariaDB devreye alınamadı.` }
            }

            return { success: false, message: 'Bilinmeyen servis.' }
        } catch (error: any) {
            console.error('Service start error:', error)
            return { success: false, message: `Hata: ${error.message}` }
        }
    })

    ipcMain.handle('services:stop', async (_event, serviceName: string) => {
        const success = await processManager.stopService(serviceName)
        return { success, message: success ? `${serviceName} durduruldu.` : `${serviceName} zaten durmuş.` }
    })

    ipcMain.handle('services:status', async () => {
        return processManager.getStatuses()
    })

    ipcMain.handle('services:logs', async (_event, serviceName: string) => {
        return processManager.getLogs(serviceName)
    })

    // Binary management
    ipcMain.handle('binaries:list-php', async () => {
        return phpManagerService.getVersions()
    })

    ipcMain.handle('binaries:download-php', async (event, id: string) => {
        const versions = await phpManagerService.getVersions()
        const version = versions.find(v => v.id === id)
        if (!version) return { success: false, message: 'Geçersiz sürüm.' }

        try {
            // Signal immediate start
            phpManagerService.updateProgress(id, 0, 'downloading')
            event.sender.send('binaries:progress', { id, progress: 0 })

            await downloadService.downloadAndExtract(version.url, id, (p) => {
                phpManagerService.updateProgress(id, p)
                event.sender.send('binaries:progress', { id, progress: p })
            })

            phpManagerService.updateProgress(id, 100, 'installed')
            // Regenerate aliases after install
            await cliAliasService.generateAliases()
            return { success: true, message: 'İndirme tamamlandı.' }
        } catch (error: any) {
            phpManagerService.updateProgress(id, 0, 'available')
            return { success: false, message: `Hata: ${error.message}` }
        }
    })

    ipcMain.handle('php:extensions:get', async (_event, version: string) => {
        return await phpManagerService.getExtensions(version)
    })

    ipcMain.handle('php:extensions:toggle', async (_event, { version, extName, enabled }) => {
        const result = await phpManagerService.toggleExtension(version, extName, enabled)
        if (result.success) {
            const serviceName = `php:${version}`
            if (processManager.isServiceRunning(serviceName)) {
                await processManager.stopService(serviceName)
                result.message += " (Service stopped for restart)"
            }
        }
        return result
    })

    ipcMain.handle('php:config:get', async (_event, version: string) => {
        const phpDir = path.join(configService.getBasePath(), 'bin', `php-${version}`)
        const iniPath = path.join(phpDir, 'php.ini')
        if (fs.existsSync(iniPath)) {
            return {
                content: fs.readFileSync(iniPath, 'utf8'),
                path: iniPath
            }
        }
        return { content: '', path: iniPath }
    })

    ipcMain.handle('php:config:save', async (_event, { version, content }) => {
        const phpDir = path.join(configService.getBasePath(), 'bin', `php-${version}`)
        const iniPath = path.join(phpDir, 'php.ini')
        fs.writeFileSync(iniPath, content)

        const serviceName = `php:${version}`
        if (processManager.isServiceRunning(serviceName)) {
            await processManager.stopService(serviceName)
        }

        return { success: true, message: 'Configuration saved.' }
    })

    // MariaDB Versions
    ipcMain.handle('mariadb:versions', async () => {
        return await mariaDbManagerService.getVersions()
    })

    ipcMain.handle('mariadb:download', async (event, id: string) => {
        const versions = await mariaDbManagerService.getVersions()
        const version = versions.find(v => v.id === id)
        if (!version) return { success: false, message: 'Geçersiz MariaDB sürümü.' }

        try {
            mariaDbManagerService.updateProgress(id, 0, 'downloading')
            event.sender.send('mariadb:progress', { id, progress: 0 })

            await downloadService.downloadAndExtract(version.url, id, (p) => {
                mariaDbManagerService.updateProgress(id, p)
                event.sender.send('mariadb:progress', { id, progress: p })
            })

            mariaDbManagerService.updateProgress(id, 100, 'installed')
            // Regenerate aliases after install
            await cliAliasService.generateAliases()
            return { success: true, message: 'MariaDB indirme tamamlandı.' }
        } catch (error: any) {
            mariaDbManagerService.updateProgress(id, 0, 'available')
            return { success: false, message: `MariaDB hatası: ${error.message}` }
        }
    })

    // Apache Versions
    ipcMain.handle('apache:versions', async () => {
        return await apacheManagerService.getVersions()
    })

    ipcMain.handle('apache:download', async (event, id: string) => {
        const versions = await apacheManagerService.getVersions()
        const version = versions.find(v => v.id === id)
        if (!version) return { success: false, message: 'Geçersiz Apache sürümü.' }

        try {
            apacheManagerService.updateProgress(id, 0, 'downloading')
            event.sender.send('apache:progress', { id, progress: 0 })

            await downloadService.downloadAndExtract(version.url, id, (p) => {
                apacheManagerService.updateProgress(id, p)
                event.sender.send('apache:progress', { id, progress: p })
            })

            apacheManagerService.updateProgress(id, 100, 'installed')
            return { success: true, message: 'Apache indirme tamamlandı.' }
        } catch (error: any) {
            apacheManagerService.updateProgress(id, 0, 'available')
            return { success: false, message: `Apache hatası: ${error.message}` }
        }
    })

    // Nginx Versions
    ipcMain.handle('nginx:versions', async () => {
        return await nginxManagerService.getVersions()
    })

    ipcMain.handle('nginx:download', async (event, id: string) => {
        const versions = await nginxManagerService.getVersions()
        const version = versions.find(v => v.id === id)
        if (!version) return { success: false, message: 'Geçersiz Nginx sürümü.' }

        try {
            nginxManagerService.updateProgress(id, 0, 'downloading')
            event.sender.send('nginx:progress', { id, progress: 0 })

            await downloadService.downloadAndExtract(version.url, id, (p) => {
                nginxManagerService.updateProgress(id, p)
                event.sender.send('nginx:progress', { id, progress: p })
            })

            nginxManagerService.updateProgress(id, 100, 'installed')
            return { success: true, message: 'Nginx indirme tamamlandı.' }
        } catch (error: any) {
            nginxManagerService.updateProgress(id, 0, 'available')
            return { success: false, message: `Nginx hatası: ${error.message}` }
        }
    })

    ipcMain.handle('dialog:select-directory', async () => {
        const result = await dialog.showOpenDialog({
            properties: ['openDirectory']
        })
        if (result.canceled) return null
        return result.filePaths[0]
    })

    ipcMain.handle('dialog:select-file', async (_event, filters: any[]) => {
        const result = await dialog.showOpenDialog({
            properties: ['openFile'],
            filters: filters || [
                { name: 'SQL & Archives', extensions: ['sql', 'zip', 'gz', 'tar'] }
            ]
        })
        if (result.canceled) return null
        return result.filePaths[0]
    })

    ipcMain.handle('dialog:save-file', async (_event, filters: any[]) => {
        const result = await dialog.showSaveDialog({
            filters: filters || [
                { name: 'SQL File', extensions: ['sql'] },
                { name: 'Compressed SQL', extensions: ['sql.gz'] }
            ]
        })
        if (result.canceled) return null
        return result.filePath
    })

    ipcMain.handle('shell:open-path', async (_event, pathStr: string) => {
        return await shell.openPath(pathStr)
    })

    ipcMain.handle('binaries:download', async (_event, { name, url }) => {
        const result = await downloadService.downloadAndExtract(url, name, (p) => {
            // TODO: Emit progress to renderer via webContents.send
            console.log(`Download progress for ${name}: ${p}%`)
        })
        await cliAliasService.generateAliases()
        return result
    })

    ipcMain.handle('cli:generate-aliases', async () => {
        try {
            await cliAliasService.generateAliases()
            return {
                success: true,
                message: 'CLI aliasları başarıyla oluşturuldu.',
                paths: {
                    powershell: configService.getGeneratedPath('aliases.ps1'),
                    bash: configService.getGeneratedPath('aliases.sh')
                }
            }
        } catch (error: any) {
            return { success: false, message: `Hata: ${error.message}` }
        }
    })

    // Project management
    ipcMain.handle('projects:list', async () => {
        return projectService.getProjects()
    })

    ipcMain.handle('projects:add', async (_event, project) => {
        const result = await projectService.addProject(project)
        // Trigger Nginx restart to generate initial config and apply
        await restartNginx()
        return result
    })

    ipcMain.handle('projects:remove', async (_event, id) => {
        const result = projectService.removeProject(id)
        // Trigger Nginx restart to remove config from glob inclusion indirectly
        // Actually we might want to delete the .conf file too
        const projects = await projectService.getProjects()
        const projectToRemove = projects.find(p => p.id === id)
        if (projectToRemove) {
            const configPath = path.join(configService.getBasePath(), 'generated_configs', 'projects', `${projectToRemove.host}.conf`)
            if (fs.existsSync(configPath)) fs.unlinkSync(configPath)
        }
        await restartNginx()
        return result
    })
    ipcMain.handle('projects:update', async (_event, project) => {
        // Clean up old config file if host changed
        const projects = projectService.getProjects()
        const oldProject = projects.find(p => p.id === project.id)
        if (oldProject && oldProject.host !== project.host) {
            const oldConfigPath = path.join(configService.getBasePath(), 'generated_configs', 'projects', `${oldProject.host}.conf`)
            if (fs.existsSync(oldConfigPath)) {
                try { fs.unlinkSync(oldConfigPath) } catch (e) { console.error('Error deleting old config:', e) }
            }
        }

        const result = projectService.updateProject(project)
        // Trigger Nginx restart
        await restartNginx()
        return result
    })

    // Config management
    ipcMain.handle('config:get', async () => {
        return configService.getSettings()
    })

    ipcMain.handle('config:save', async (_event, config: any) => {
        const settings = configService.updateSettings(config)
        return { success: true, settings }
    })

    // Nginx Config Management
    ipcMain.handle('nginx:config:get', async () => {
        const configPath = path.join(configService.getBasePath(), 'generated_configs', 'nginx.conf')
        if (fs.existsSync(configPath)) {
            return fs.readFileSync(configPath, 'utf8')
        }
        return ''
    })

    ipcMain.handle('nginx:config:save', async (_event, content) => {
        const configPath = path.join(configService.getBasePath(), 'generated_configs', 'nginx.conf')
        fs.writeFileSync(configPath, content)
        // Full restart after manual global save
        return await restartNginx()
    })

    ipcMain.handle('nginx:config:test', async () => {
        try {
            const binDir = path.join(configService.getBasePath(), 'bin', 'nginx')
            const nginxVersions = fs.readdirSync(binDir).filter(f => fs.statSync(path.join(binDir, f)).isDirectory())
            const activeVersion = nginxVersions[0]
            if (!activeVersion) throw new Error('Nginx not found')

            const nginxPrefix = path.join(binDir, activeVersion)
            const binPath = path.join(nginxPrefix, 'nginx.exe')
            const configPath = path.join(configService.getBasePath(), 'generated_configs', 'nginx.conf')

            const result = await processManager.runOnce(binPath, ['-t', '-p', nginxPrefix, '-c', configPath], 'nginx')
            return { success: result.success, message: result.success ? 'Configuration test successful' : result.output }
        } catch (error: any) {
            return { success: false, message: error.message }
        }
    })

    // Project Nginx Config
    ipcMain.handle('project:nginx:get', async (_event, host) => {
        const configPath = path.join(configService.getBasePath(), 'generated_configs', 'projects', `${host}.conf`)
        if (fs.existsSync(configPath)) {
            return fs.readFileSync(configPath, 'utf8')
        }
        return ''
    })

    ipcMain.handle('project:nginx:test', async (_event, host, content) => {
        const configPath = path.join(configService.getBasePath(), 'generated_configs', 'projects', `${host}.conf`)
        let originalContent = ''
        if (fs.existsSync(configPath)) {
            originalContent = fs.readFileSync(configPath, 'utf8')
        }

        try {
            // 1. Save new content temporarily
            fs.writeFileSync(configPath, content)

            // 2. Run global test
            const binDir = path.join(configService.getBasePath(), 'bin', 'nginx')
            const nginxVersions = fs.readdirSync(binDir).filter(f => fs.statSync(path.join(binDir, f)).isDirectory())
            const activeVersion = nginxVersions[0]
            if (!activeVersion) throw new Error('Nginx sürümü bulunamadı.')

            const nginxPrefix = path.join(binDir, activeVersion)
            const binPath = path.join(nginxPrefix, 'nginx.exe')
            const globalConfigPath = path.join(configService.getBasePath(), 'generated_configs', 'nginx.conf')

            const result = await processManager.runOnce(binPath, ['-t', '-p', nginxPrefix, '-c', globalConfigPath], 'nginx')

            // 3. Restore original content regardless of test result
            // (The user must click "Save" to keep it)
            if (originalContent) {
                fs.writeFileSync(configPath, originalContent)
            } else {
                fs.unlinkSync(configPath)
            }

            return { success: result.success, message: result.success ? 'Configuration test successful' : result.output }
        } catch (error: any) {
            // Restore on error too
            if (originalContent) fs.writeFileSync(configPath, originalContent)
            return { success: false, message: error.message }
        }
    })

    ipcMain.handle('project:nginx:save', async (_event, host, content) => {
        const configPath = path.join(configService.getBasePath(), 'generated_configs', 'projects', `${host}.conf`)
        // Ensure manual edit marker is present
        let finalContent = content
        if (!finalContent.includes('# MANUAL_EDIT')) {
            finalContent = `# MANUAL_EDIT\n${finalContent}`
        }
        fs.writeFileSync(configPath, finalContent)
        return await restartNginx()
    })

    // phpMyAdmin
    ipcMain.handle('pma:status', async () => {
        return await phpMyAdminService.isInstalled()
    })

    ipcMain.handle('pma:setup', async (event, mariaDbPort: string) => {
        return await phpMyAdminService.setup(mariaDbPort, (p) => {
            event.sender.send('pma:progress', p)
        })
    })

    ipcMain.handle('services:reset-data', async (_event, serviceName: string) => {
        try {
            await processManager.forceKillAll(serviceName)

            const versionMatch = serviceName.match(/^(?:mariadb|mysql):(.+)$/)
            const dbVersion = versionMatch ? versionMatch[1] : null
            const dbId = dbVersion ? `mariadb-${dbVersion}` : null

            if (!dbId) return { success: false, message: 'Geçersiz servis adı.' }

            const dataDir = path.join(configService.getBasePath(), 'data', dbId)
            if (fs.existsSync(dataDir)) {
                fs.rmSync(dataDir, { recursive: true, force: true })
            }
            return { success: true, message: `${serviceName} verileri sıfırlandı. Tekrar başlatmayı deneyebilirsiniz.` }
        } catch (error: any) {
            return { success: false, message: `Sıfırlama hatası: ${error.message}` }
        }
    })

    // MariaDB Operations
    ipcMain.handle('mariadb:import-wizard:check-db', async (_event, { versionId, dbName, rootPass }) => {
        const versions = await mariaDbManagerService.getVersions()
        const v = versions.find(v => v.id === versionId)
        if (!v) return { exists: false, error: 'MariaDB version not found' }

        const binDir = path.join(configService.getBasePath(), 'bin', versionId)
        const isWindows = process.platform === 'win32'
        const binPath = findExecutable(binDir, isWindows ? 'mariadb.exe' : 'mariadb') || findExecutable(binDir, isWindows ? 'mysql.exe' : 'mysql')
        if (!binPath) return { exists: false, error: 'mariadb/mysql executable not found' }

        const exists = await mariaDbOperationService.checkDatabaseExists({
            binPath,
            host: '127.0.0.1',
            port: v.port,
            rootUser: 'root',
            rootPass: rootPass || ''
        }, dbName)

        return { exists }
    })

    ipcMain.handle('mariadb:import-wizard:start', async (event, { versionId, filePath, dbName, user, pass, rootPass, overwrite }) => {
        const versions = await mariaDbManagerService.getVersions()
        const v = versions.find(v => v.id === versionId)
        if (!v) return { success: false, message: 'MariaDB version not found' }

        const binDir = path.join(configService.getBasePath(), 'bin', versionId)
        const isWindows = process.platform === 'win32'
        const dbBin = findExecutable(binDir, isWindows ? 'mariadb.exe' : 'mariadb') || findExecutable(binDir, isWindows ? 'mysql.exe' : 'mysql')
        if (!dbBin) return { success: false, message: 'mariadb/mysql executable not found' }

        const config = {
            binPath: dbBin,
            host: '127.0.0.1',
            port: v.port,
            rootUser: 'root',
            rootPass: rootPass || ''
        }

        const log = (msg: string) => event.sender.send('mariadb:import:log', msg)

        try {
            if (overwrite) {
                log(`Dropping existing database: ${dbName}`)
                await mariaDbOperationService.dropDatabase(config, dbName)
            }

            log(`Creating database and user: ${dbName} / ${user}`)
            const createRes = await mariaDbOperationService.createDatabaseAndUser(config, dbName, user, pass)
            if (!createRes.success) return createRes

            let sqlFiles: string[] = []
            if (filePath.toLowerCase().endsWith('.sql')) {
                sqlFiles = [filePath]
            } else {
                log(`Extracting archive: ${path.basename(filePath)}`)
                const extractDir = path.join(app.getPath('temp'), `mariadb_import_${Date.now()}`)
                sqlFiles = await mariaDbOperationService.extractArchive(filePath, extractDir)
                if (sqlFiles.length === 0) return { success: false, message: 'No .sql files found in archive.' }
            }

            for (const sqlFile of sqlFiles) {
                log(`Importing: ${path.basename(sqlFile)}`)
                const importRes = await mariaDbOperationService.importSql(config, dbName, sqlFile, (msg) => log(msg))
                if (!importRes.success) return importRes
            }

            return { success: true, message: 'Import completed successfully.' }
        } catch (error: any) {
            return { success: false, message: `Import error: ${error.message}` }
        }
    })

    ipcMain.handle('mariadb:export-wizard:list-dbs', async (_event, { versionId, rootPass }) => {
        const versions = await mariaDbManagerService.getVersions()
        const v = versions.find(v => v.id === versionId)
        if (!v) return []

        const binDir = path.join(configService.getBasePath(), 'bin', versionId)
        const isWindows = process.platform === 'win32'
        const dbBin = findExecutable(binDir, isWindows ? 'mariadb.exe' : 'mariadb') || findExecutable(binDir, isWindows ? 'mysql.exe' : 'mysql')
        if (!dbBin) return []

        return await mariaDbOperationService.listDatabases({
            binPath: dbBin,
            host: '127.0.0.1',
            port: v.port,
            rootUser: 'root',
            rootPass: rootPass || ''
        })
    })

    ipcMain.handle('mariadb:export-wizard:start', async (event, { versionId, dbName, savePath, compress, rootPass }) => {
        const versions = await mariaDbManagerService.getVersions()
        const v = versions.find(v => v.id === versionId)
        if (!v) return { success: false, message: 'MariaDB version not found' }

        const binDir = path.join(configService.getBasePath(), 'bin', versionId)
        const isWindows = process.platform === 'win32'
        const dbBin = findExecutable(binDir, isWindows ? 'mariadb.exe' : 'mariadb') || findExecutable(binDir, isWindows ? 'mysql.exe' : 'mysql')
        if (!dbBin) return { success: false, message: 'mariadb/mysql executable not found' }

        const log = (msg: string) => event.sender.send('mariadb:export:log', msg)

        return await mariaDbOperationService.exportSql({
            binPath: dbBin,
            host: '127.0.0.1',
            port: v.port,
            rootUser: 'root',
            rootPass: rootPass || ''
        }, dbName, savePath, compress, (msg) => log(msg))
    })
}
