#!/usr/bin/env node

// saeeol postinstall — downloads platform binary from GitHub Releases
const https = require("https")
const http = require("http")
const fs = require("fs")
const path = require("path")
const zlib = require("zlib")
const { execSync } = require("child_process")

const REPO = "byfabulist/saeeol"
const VERSION = require("./package.json").version

function getPlatformInfo() {
  const archMap = { x64: "x64", arm64: "arm64" }
  const platformMap = { win32: "windows", darwin: "darwin", linux: "linux" }
  const p = platformMap[process.platform] || process.platform
  const a = archMap[process.arch] || process.arch
  const ext = process.platform === "win32" ? ".zip" : ".tar.gz"
  const archiveName = `saeeol-${p}-${a}${ext}`
  const binaryName = process.platform === "win32" ? "saeeol.exe" : "saeeol"
  return { archiveName, binaryName, platform: p, arch: a }
}

function fetch(url, redirects = 5) {
  return new Promise((resolve, reject) => {
    const mod = url.startsWith("https") ? https : http
    mod.get(url, { timeout: 60000 }, (res) => {
      if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
        if (redirects <= 0) return reject(new Error("Too many redirects"))
        return fetch(res.headers.location, redirects - 1).then(resolve, reject)
      }
      if (res.statusCode !== 200) {
        return reject(new Error(`HTTP ${res.statusCode} for ${url}`))
      }
      const chunks = []
      res.on("data", (chunk) => chunks.push(chunk))
      res.on("end", () => resolve(Buffer.concat(chunks)))
      res.on("error", reject)
    }).on("error", reject)
  })
}

async function extractTarGz(buffer, destDir, binaryName) {
  // Use tar on non-windows, or platform tar on windows (git bash)
  const tmpFile = path.join(destDir, "download.tar.gz")
  fs.writeFileSync(tmpFile, buffer)
  try {
    if (process.platform === "win32") {
      // Try PowerShell Expand-Archive for .tar.gz or just use tar if available
      try {
        execSync(`tar -xzf "${tmpFile}" -C "${destDir}"`, { stdio: "pipe", windowsHide: true })
      } catch {
        // Fallback: use zlib + tar parsing manually not practical, try powershell
        throw new Error("tar command not available on Windows. Install Git Bash or add tar to PATH.")
      }
    } else {
      execSync(`tar -xzf "${tmpFile}" -C "${destDir}"`, { stdio: "pipe" })
    }
  } finally {
    try { fs.unlinkSync(tmpFile) } catch {}
  }
}

async function extractZip(buffer, destDir, binaryName) {
  if (process.platform === "win32") {
    const tmpFile = path.join(destDir, "download.zip")
    fs.writeFileSync(tmpFile, buffer)
    try {
      execSync(`powershell -Command "Expand-Archive -Path '${tmpFile}' -DestinationPath '${destDir}' -Force"`, {
        stdio: "pipe",
        windowsHide: true,
      })
    } finally {
      try { fs.unlinkSync(tmpFile) } catch {}
    }
  } else {
    // On non-windows, try unzip
    const tmpFile = path.join(destDir, "download.zip")
    fs.writeFileSync(tmpFile, buffer)
    try {
      execSync(`unzip -o "${tmpFile}" -d "${destDir}"`, { stdio: "pipe" })
    } finally {
      try { fs.unlinkSync(tmpFile) } catch {}
    }
  }
}

async function main() {
  const { archiveName, binaryName, platform: p, arch: a } = getPlatformInfo()
  const binDir = path.join(__dirname, "download")

  // Check if binary already exists
  const binaryPath = path.join(binDir, binaryName)
  if (fs.existsSync(binaryPath)) {
    console.log(`saeeol binary already exists at ${binaryPath}`)
    return
  }

  fs.mkdirSync(binDir, { recursive: true })

  const url = `https://github.com/${REPO}/releases/download/v${VERSION}/${archiveName}`
  console.log(`Downloading saeeol v${VERSION} for ${p}-${a}...`)
  console.log(`  ${url}`)

  let buffer
  try {
    buffer = await fetch(url)
  } catch (err) {
    // Fallback: try without version tag (latest)
    const fallbackUrl = `https://github.com/${REPO}/releases/latest/download/${archiveName}`
    console.log(`Version-specific download failed: ${err.message}`)
    console.log(`Trying latest: ${fallbackUrl}`)
    try {
      buffer = await fetch(fallbackUrl)
    } catch (err2) {
      console.error(`Failed to download saeeol binary: ${err2.message}`)
      console.error(`Please download manually from: https://github.com/${REPO}/releases`)
      process.exit(0) // Don't fail npm install
    }
  }

  console.log(`Downloaded ${(buffer.length / 1024 / 1024).toFixed(1)} MB`)

  // Extract
  if (archiveName.endsWith(".tar.gz")) {
    await extractTarGz(buffer, binDir, binaryName)
  } else {
    await extractZip(buffer, binDir, binaryName)
  }

  // Verify
  if (!fs.existsSync(binaryPath)) {
    // The archive might extract to a subdirectory, search for the binary
    const files = fs.readdirSync(binDir, { recursive: true })
    const found = files.find((f) => {
      const basename = path.basename(f)
      return basename === "saeeol" || basename === "saeeol.exe"
    })
    if (found) {
      const fullPath = path.join(binDir, found)
      fs.copyFileSync(fullPath, binaryPath)
    }
  }

  if (fs.existsSync(binaryPath)) {
    if (process.platform !== "win32") {
      fs.chmodSync(binaryPath, 0o755)
    }
    console.log(`saeeol v${VERSION} installed successfully!`)
    console.log(`  Binary: ${binaryPath}`)
  } else {
    console.warn(`Warning: binary not found after extraction at ${binaryPath}`)
    console.warn(`You may need to install manually from https://github.com/${REPO}/releases`)
  }
}

main().catch((err) => {
  console.error(`saeeol postinstall failed: ${err.message}`)
  console.error(`Install manually: https://github.com/${REPO}/releases`)
  process.exit(0) // Don't fail npm install
})
