import axios from 'axios'
import fs from 'fs'
import path from 'path'
import { app } from 'electron'
import { configService } from './ConfigService'
const decompress = require('decompress')

export class DownloadService {
    private binDir: string

    constructor() {
        // Use local base path for binaries
        this.binDir = path.join(configService.getBasePath(), 'bin')
        if (!fs.existsSync(this.binDir)) {
            fs.mkdirSync(this.binDir, { recursive: true })
        }
    }

    async downloadAndExtract(url: string, targetName: string, onProgress?: (p: number) => void, customTargetDir?: string): Promise<string> {
        const isTarGz = url.toLowerCase().endsWith('.tar.gz') || url.toLowerCase().endsWith('.tgz');
        const extension = isTarGz ? '.tar.gz' : '.zip';
        const tempFile = path.join(app.getPath('temp'), `${targetName}${extension}`)
        const targetDir = customTargetDir || path.join(this.binDir, targetName)

        // Cleanup failed/previous attempts if we want a fresh start
        // For phpMyAdmin, we always want a fresh extract to avoid version mix
        if (fs.existsSync(targetDir) && !customTargetDir) {
            // For PHP/MySQL we might skip, but let's make it smarter
        }

        const writer = fs.createWriteStream(tempFile)

        try {
            const response = await axios({
                url,
                method: 'GET',
                responseType: 'stream',
                headers: {
                    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
                    'Referer': url.includes('mysql.com') ? 'https://dev.mysql.com/downloads/mysql/' : undefined
                }
            })

            const totalLength = parseInt(response.headers['content-length'] || '0')
            let downloadedLength = 0

            response.data.on('data', (chunk: any) => {
                downloadedLength += chunk.length
                if (onProgress && totalLength > 0) {
                    onProgress(Math.round((downloadedLength / totalLength) * 100))
                }
            })

            response.data.pipe(writer)

            return new Promise((resolve, reject) => {
                writer.on('finish', async () => {
                    try {
                        await decompress(tempFile, targetDir)
                        if (fs.existsSync(tempFile)) fs.unlinkSync(tempFile)
                        resolve(targetDir)
                    } catch (err) {
                        reject(err)
                    }
                })
                writer.on('error', reject)
            })
        } catch (error) {
            if (fs.existsSync(tempFile)) fs.unlinkSync(tempFile)
            throw error
        }
    }

    getBinPath(service: string, executable: string): string {
        const isWindows = process.platform === 'win32';
        const fullExecutable = isWindows ? (executable.endsWith('.exe') ? executable : `${executable}.exe`) : executable;
        return path.join(this.binDir, service, fullExecutable)
    }
}

export const downloadService = new DownloadService()
