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

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

export class MySqlManagerService {
    private versions: MySqlVersion[] = []
    private binDir: string
    private catalogPath: string

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

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

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

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

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

                // Extract MAJOR.MINOR (e.g. 8.0 from 8.0.40)
                const versionParts = version.split('.')
                const majorMinor = `${versionParts[0]}.${versionParts[1]}`

                // Working CDN Pattern: https://cdn.mysql.com/archives/mysql-MAJOR.MINOR/mysql-VERSION-winx64.zip
                const url = `https://cdn.mysql.com/archives/mysql-${majorMinor}/mysql-${version}-winx64.zip`

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

                return {
                    id: `mysql-${version}`,
                    version,
                    cycle,
                    url,
                    status: 'available',
                    progress: 0,
                    port: customPort,
                    description: v.status
                }
            })

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

    private updateVersionsList(newList: MySqlVersion[]) {
        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() {
        this.versions = this.versions.map(v => {
            const targetDir = path.join(this.binDir, v.id)
            const possiblePaths = [
                path.join(targetDir, 'bin', 'mysqld.exe'),
                path.join(targetDir, `mysql-${v.version}-winx64`, 'bin', 'mysqld.exe')
            ]

            const isInstalled = possiblePaths.some(p => fs.existsSync(p))

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

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

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

export const mySqlManagerService = new MySqlManagerService()
