import fs from 'fs'
import path from 'path'
import { app } from 'electron'
import { configService } from './ConfigService'

export interface MariaDbVersion {
    id: string
    version: string
    cycle: string
    url: string
    status: 'available' | 'downloading' | 'installed'
    progress: number
    port: string
    description?: string
}

export class MariaDbManagerService {
    private versions: MariaDbVersion[] = []
    private binDir: string
    private catalogPath: string

    constructor() {
        this.binDir = path.join(configService.getBasePath(), 'bin')
        this.catalogPath = path.join(app.getAppPath(), 'src/main/resources/mariadb_catalog.json')
        if (!fs.existsSync(this.catalogPath)) {
            this.catalogPath = path.join(process.cwd(), 'src/main/resources/mariadb_catalog.json')
        }
        this.init()
    }

    private async init() {
        if (!fs.existsSync(this.binDir)) {
            fs.mkdirSync(this.binDir, { recursive: true })
        }
    }

    async fetchAvailableVersions(): Promise<MariaDbVersion[]> {
        console.log('Loading MariaDB versions from local catalog:', this.catalogPath)
        try {
            if (!fs.existsSync(this.catalogPath)) {
                console.error('MariaDB Catalog not found at:', this.catalogPath)
                return this.versions
            }

            const rawData = fs.readFileSync(this.catalogPath, 'utf8')
            const catalog = JSON.parse(rawData)
            const releases = catalog.mariadb_release_catalog.releases as any[]

            const platform = process.platform; // win32, darwin, linux
            const arch = process.arch; // x64, arm64

            const dynamicVersions: MariaDbVersion[] = releases.map((v, index) => {
                const version = v.version
                const cycle = v.series

                // Resolve URL based on platform and architecture
                let url = '';
                if (v.platforms && v.platforms[platform]) {
                    url = v.platforms[platform][arch] || v.platforms[platform]['x64'] || '';
                }

                if (!url) {
                    console.warn(`No MariaDB URL found for platform ${platform}/${arch} in version ${version}`);
                }

                const settings = configService.getSettings()
                const defaultPort = (3306 + index).toString()
                const customPort = settings.mariaDbPorts?.[`mariadb-${version}`] || defaultPort

                return {
                    id: `mariadb-${version}`,
                    version,
                    cycle,
                    url,
                    status: 'available' as MariaDbVersion['status'],
                    progress: 0,
                    port: customPort,
                    description: v.status
                }
            }).filter(v => v.url !== '') // Only include versions available for this platform

            this.updateVersionsList(dynamicVersions)
            return this.versions
        } catch (e: any) {
            console.error('Failed to load MariaDB catalog:', e.message)
            return this.versions
        }
    }

    private updateVersionsList(newList: MariaDbVersion[]) {
        this.versions = newList.map(dv => {
            const current = this.versions.find(cv => cv.id === dv.id)
            if (current && current.status === 'downloading') return current
            return dv
        }).sort((a, b) => b.version.localeCompare(a.version, undefined, { numeric: true, sensitivity: 'base' }))

        this.refreshInstalledStatus()
    }

    private refreshInstalledStatus() {
        const isWindows = process.platform === 'win32';
        const binaryName = isWindows ? 'mariadbd.exe' : 'mariadbd';

        this.versions = this.versions.map(v => {
            const targetDir = path.join(this.binDir, v.id)
            const possibleBinPaths = [
                path.join(targetDir, 'bin', binaryName),
                // Some MariaDB distributions have nested folders after zip/tar extraction
                path.join(targetDir, `mariadb-${v.version}-${isWindows ? 'winx64' : (process.arch === 'arm64' ? 'macosx-arm64' : 'macosx-x86_64')}`, 'bin', binaryName),
                path.join(targetDir, `mariadb-${v.version}-${isWindows ? 'winx64' : 'linux-systemd-x86_64'}`, 'bin', binaryName)
            ];

            const isInstalled = possibleBinPaths.some(p => fs.existsSync(p));

            if (isInstalled) {
                return { ...v, status: 'installed', progress: 100 }
            }
            return v
        })
    }

    async getVersions(): Promise<MariaDbVersion[]> {
        if (this.versions.length === 0) {
            await this.fetchAvailableVersions()
        } else {
            this.refreshInstalledStatus()
        }
        return this.versions
    }

    updateProgress(id: string, progress: number, status: MariaDbVersion['status'] = 'downloading') {
        const version = this.versions.find(v => v.id === id)
        if (version) {
            version.progress = progress
            version.status = status
        }
    }

    async getMariaDbBinaryPath(version: string): Promise<string | null> {
        const isWindows = process.platform === 'win32'
        const binaryName = isWindows ? 'mariadbd.exe' : 'mariadbd'
        const targetDir = path.join(this.binDir, `mariadb-${version}`)

        const possibleBinPaths = [
            path.join(targetDir, 'bin', binaryName),
            path.join(targetDir, `mariadb-${version}-${isWindows ? 'winx64' : (process.arch === 'arm64' ? 'macosx-arm64' : 'macosx-x86_64')}`, 'bin', binaryName),
            path.join(targetDir, `mariadb-${version}-${isWindows ? 'winx64' : 'linux-systemd-x86_64'}`, 'bin', binaryName)
        ]

        for (const p of possibleBinPaths) {
            if (fs.existsSync(p)) {
                // Return mysql/mariadb client instead of the daemon for CLI usage
                const clientName = isWindows ? 'mysql.exe' : 'mysql'
                return path.join(path.dirname(p), clientName)
            }
        }
        return null
    }
}

export const mariaDbManagerService = new MariaDbManagerService()
