import { defineConfig, type Plugin } from 'vite'
import react from '@vitejs/plugin-react'
import tailwindcss from '@tailwindcss/vite'
import path from 'node:path'
import fs from 'node:fs'

/**
 * /audio/<prefix>/... → a real directory, from audio-mounts.json (shared with
 * serve.py so dev and production resolve identically). Longest prefix wins; ""
 * is the fallback mount. Masters are gigabytes and live outside the repo, so
 * they are mounted, never copied into the bundle.
 */
function loadMounts(): [string, string][] {
  try {
    const cfg = JSON.parse(fs.readFileSync(path.resolve(__dirname, 'audio-mounts.json'), 'utf8'))
    return Object.entries(cfg.mounts as Record<string, string>)
      .map(([k, v]) => [k, path.resolve(__dirname, v)] as [string, string])
      .sort((a, b) => b[0].length - a[0].length) // longest prefix first
  } catch {
    return [['', path.resolve(__dirname, '../tide-table/punkachien')]]
  }
}

/**
 * Dev-only: serve /audio/* with HTTP Range support, so wavesurfer can stream +
 * seek the big FLACs without copying them into the bundle. In production,
 * `serve.py --dir dist` reads the same mounts, keeping /audio stable everywhere.
 */
const AUDIO_MIME: Record<string, string> = {
  '.flac': 'audio/flac', '.wav': 'audio/wav', '.aif': 'audio/aiff',
  '.aiff': 'audio/aiff', '.mp3': 'audio/mpeg', '.ogg': 'audio/ogg',
  '.opus': 'audio/ogg', '.m4a': 'audio/mp4',
}

function audioDevServer(): Plugin {
  const mounts = loadMounts()
  return {
    name: 'armada-audio-dev',
    apply: 'serve',
    configureServer(server) {
      server.middlewares.use('/audio', (req, res, next) => {
        const rel = decodeURIComponent((req.url || '').split('?')[0]).replace(/^\/+/, '')
        const hit = mounts.find(([p]) => p === '' || rel === p || rel.startsWith(p + '/'))
        if (!hit) return next()
        const [prefix, dir] = hit
        const file = path.join(dir, prefix ? rel.slice(prefix.length) : rel)
        if (!file.startsWith(dir) || !fs.existsSync(file) || !fs.statSync(file).isFile())
          return next()
        const size = fs.statSync(file).size
        const range = req.headers.range
        res.setHeader('Accept-Ranges', 'bytes')
        // by extension, not a constant: the masters are FLAC but the sample kits are
        // WAV, and a wrong Content-Type is the kind of thing that works in one browser
        // and silently refuses to decode in the next. serve.py uses guess_type for the
        // same reason.
        res.setHeader('Content-Type', AUDIO_MIME[path.extname(file).toLowerCase()] || 'application/octet-stream')
        if (range) {
          const m = /bytes=(\d*)-(\d*)/.exec(range)
          const start = m && m[1] ? parseInt(m[1], 10) : 0
          const end = m && m[2] ? parseInt(m[2], 10) : size - 1
          res.statusCode = 206
          res.setHeader('Content-Range', `bytes ${start}-${end}/${size}`)
          res.setHeader('Content-Length', String(end - start + 1))
          fs.createReadStream(file, { start, end }).pipe(res)
        } else {
          res.setHeader('Content-Length', String(size))
          fs.createReadStream(file).pipe(res)
        }
      })
    },
  }
}

// https://vite.dev/config/
export default defineConfig({
  plugins: [react(), tailwindcss(), audioDevServer()],
  resolve: { alias: { '@': path.resolve(__dirname, './src') } },
  server: { host: true }, // expose on LAN for phone audition (same wifi)
  build: {
    rollupOptions: {
      input: {
        // Multi-page: the A/B take-judge (index), the distribution simulator
        // (sextant), and the set-judge (judge) — go/no-go across a whole gig.
        main: path.resolve(__dirname, 'index.html'),
        sextant: path.resolve(__dirname, 'sextant.html'),
        judge: path.resolve(__dirname, 'judge.html'),
        // and the boundary lab — where exactly does one track become the next
        bounds: path.resolve(__dirname, 'bounds.html'),
        // La Cale — audition the sample kits the Foundry cuts, and rack them up
        kits: path.resolve(__dirname, 'kits.html'),
      },
    },
  },
})
