import { ipcMain, app, dialog } 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 { mySqlManagerService } from '../services/MySqlManagerService'
import { nginxManagerService } from '../services/NginxManagerService'
import { phpMyAdminService } from '../services/PhpMyAdminService'
import { portMappingService } from '../services/PortMappingService'
import path from 'path'

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
}

export function registerIpcHandlers(): void {
    // Service management
    ipcMain.handle('services:reload', async (_event, serviceName: string) => {
        if (serviceName !== 'nginx') return { success: false, message: 'Yalnızca Nginx için reload desteklenmektedir.' }

        try {
            // Re-generate config
            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] // Simplify: use first installed
            if (!activeVersion) throw new Error('Nginx sürümü bulunamadı.')

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

            // For reload, we need the same prefix and config
            const success = await processManager.runOnce(binPath, ['-p', nginxPrefix, '-c', configPath, '-s', 'reload'], 'nginx')
            return { success, message: success ? 'Nginx yapılandırması yeniden yüklendi.' : 'Nginx reload hatası (Nginx çalışmıyor olabilir).' }
        } catch (error: any) {
            return { success: false, message: `Reload hatası: ${error.message}` }
        }
    })

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

            if (serviceName === 'nginx') {
                const rootPath = path.join(app.getAppPath(), 'www')
                const nginxDir = path.join(binDir, 'nginx')
                const binPath = findExecutable(nginxDir, 'nginx.exe')
                const logDir = path.join(configService.getBasePath(), 'logs')

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

                // Nginx prefix = directory containing nginx.exe
                const nginxPrefix = path.dirname(binPath)
                const confDir = path.join(nginxPrefix, 'conf')

                // Ensure temp directories exist (Nginx needs these)
                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 })
                    }
                }

                const projects = await projectService.getProjects()
                const projectsConfDir = path.join(configService.getBasePath(), 'generated_configs', 'projects')
                if (!fs.existsSync(projectsConfDir)) fs.mkdirSync(projectsConfDir, { recursive: true })

                // Clean up old project configs
                const existingFiles = fs.readdirSync(projectsConfDir)
                for (const file of existingFiles) {
                    fs.unlinkSync(path.join(projectsConfDir, file))
                }

                for (const p of projects) {
                    const phpPort = portMappingService.getPhpPort(p.phpVersion)
                    const normalizedPath = p.path.replace(/\\/g, '/')
                    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,
                    PHP_PORT: settings.phpPort,
                    ROOT: rootPath,
                    LOG_DIR: logDir.replace(/\\/g, '/'),
                    CONF_DIR: confDir.replace(/\\/g, '/'),
                    PHPMYADMIN_DIR: phpMyAdminService.getPath().replace(/\\/g, '/'),
                    PROJECTS: projectsInclusion
                })

                // Test config first with prefix
                const testResult = await processManager.runOnce(binPath, ['-t', '-p', nginxPrefix, '-c', configPath], 'nginx')
                if (!testResult) {
                    return { success: false, message: 'Nginx konfigürasyon hatası! Log sekmesini kontrol edin.' }
                }

                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.startsWith('php')) {
                const versionMatch = serviceName.match(/^php:(.+)$/)
                const phpVersion = versionMatch ? versionMatch[1] : null
                const phpId = phpVersion ? `php-${phpVersion}` : null

                const phpDir = phpId ? path.join(binDir, phpId) : binDir
                const binPath = findExecutable(phpDir, 'php-cgi.exe')

                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 configPath = await configService.generateConfig('php.ini.template', `php_${phpVersion || 'default'}.ini`, {
                    EXT_DIR: extDir,
                    GD_EXT: gdExtName,
                    SESSION_DIR: sessionDir,
                    TEMP_DIR: tempDir
                })

                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('mysql')) {
                const versionMatch = serviceName.match(/^mysql:(.+)$/)
                const mysqlVersion = versionMatch ? versionMatch[1] : null
                const mysqlId = mysqlVersion ? `mysql-${mysqlVersion}` : null

                const dataDir = mysqlId
                    ? path.join(configService.getBasePath(), 'data', mysqlId)
                    : path.join(configService.getBasePath(), 'data', 'default')

                const mysqlDir = mysqlId ? path.join(binDir, mysqlId) : binDir
                const binPath = findExecutable(mysqlDir, 'mysqld.exe')

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

                const mysqlVersions = await mySqlManagerService.getVersions()
                const mysqlInfo = mysqlVersions.find(v => v.id === mysqlId)
                const mysqlPort = mysqlInfo?.port || (mysqlId ? '3306' : settings.mysqlPort)

                // 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, mysqlPort)

                // Initialize if data directory is empty
                if (!fs.existsSync(dataDir) || fs.readdirSync(dataDir).length === 0) {
                    if (!fs.existsSync(dataDir)) fs.mkdirSync(dataDir, { recursive: true })
                    console.log(`Initializing MySQL data directory for ${serviceName}...`)

                    try {
                        // Try modern initialization first (5.7+)
                        await processManager.runOnce(binPath, ['--initialize-insecure', `--datadir=${dataDir.replace(/\\/g, '/')}`])
                    } catch (err) {
                        console.log(`Modern init failed, trying template copy for ${serviceName}...`)
                        // Fallback for 5.6: Copy default 'data' folder from binary dir if it exists
                        const templateDataDir = path.join(mysqlDir, 'data')
                        if (fs.existsSync(templateDataDir)) {
                            // Recursively copy template data (mysql, performance_schema, etc.)
                            fs.cpSync(templateDataDir, dataDir, { recursive: true })
                            console.log(`Successfully copied template data for ${serviceName}`)
                        } else {
                            throw new Error(`MySQL 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('my.ini.template', `my_${mysqlId || 'default'}.ini`, {
                    PORT: mysqlPort,
                    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 for MySQL
                    await new Promise(r => setTimeout(r, 1500))
                    if (!processManager.isServiceRunning(serviceName)) {
                        const errorLogs = await processManager.getLastErrorLogs(serviceName)
                        return { success: false, message: `${mysqlVersion || ''} MySQL 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: `${mysqlVersion || ''} MySQL başlatılamadı.\n\n${errorLogs.join('\n')}` }
                }

                return { success, message: success ? `${mysqlVersion || ''} MySQL başlatıldı.` : `${mysqlVersion || ''} MySQL 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')
            return { success: true, message: 'İndirme tamamlandı.' }
        } catch (error: any) {
            phpManagerService.updateProgress(id, 0, 'available')
            return { success: false, message: `Hata: ${error.message}` }
        }
    })

    // MySQL Versions
    ipcMain.handle('mysql:versions', async () => {
        return await mySqlManagerService.getVersions()
    })

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

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

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

            mySqlManagerService.updateProgress(id, 100, 'installed')
            return { success: true, message: 'MySQL indirme tamamlandı.' }
        } catch (error: any) {
            mySqlManagerService.updateProgress(id, 0, 'available')
            return { success: false, message: `MySQL 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('binaries:download', async (_event, { name, url }) => {
        return downloadService.downloadAndExtract(url, name, (p) => {
            // TODO: Emit progress to renderer via webContents.send
            console.log(`Download progress for ${name}: ${p}%`)
        })
    })

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

    ipcMain.handle('projects:add', async (_event, project) => {
        return projectService.addProject(project)
    })

    ipcMain.handle('projects:remove', async (_event, id) => {
        return projectService.removeProject(id)
    })
    ipcMain.handle('projects:update', async (_event, project) => {
        return projectService.updateProject(project)
    })

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

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

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

    ipcMain.handle('pma:setup', async (event, mysqlPort: string) => {
        return await phpMyAdminService.setup(mysqlPort, (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(/^mysql:(.+)$/)
            const mysqlVersion = versionMatch ? versionMatch[1] : null
            const mysqlId = mysqlVersion ? `mysql-${mysqlVersion}` : null

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

            const dataDir = path.join(configService.getBasePath(), 'data', mysqlId)
            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}` }
        }
    })
}
