import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { VitePWA } from 'vite-plugin-pwa'

export default defineConfig({
  plugins: [
    react(),
    VitePWA({
      registerType: 'autoUpdate',
      includeAssets: ['favicon-32.png', 'apple-touch-icon.png'],
      manifest: {
        name: 'Muzick',
        short_name: 'Muzick',
        description: 'Self-hosted music player and recommendation engine',
        start_url: '/',
        scope: '/',
        display: 'standalone',
        orientation: 'portrait',
        background_color: '#14110D',
        theme_color: '#14110D',
        icons: [
          { src: '/icon-192.png', sizes: '192x192', type: 'image/png' },
          { src: '/icon-512.png', sizes: '512x512', type: 'image/png' },
          {
            src: '/icon-maskable-512.png',
            sizes: '512x512',
            type: 'image/png',
            purpose: 'maskable',
          },
        ],
      },
      workbox: {
        globPatterns: ['**/*.{js,css,html,woff2}'],

        // The SPA fallback must never swallow the API: /api/playback/stream is a
        // long-lived SSE channel and the track endpoints stream audio. Both look
        // like navigations to Workbox unless they are denied here.
        navigateFallback: '/index.html',
        navigateFallbackDenylist: [/^\/api\//],

        // A waiting service worker would otherwise activate and reload the page
        // mid-song. Letting it wait means updates land on the next cold start,
        // which is the right trade for a player that runs in the background.
        skipWaiting: false,
        clientsClaim: false,

        runtimeCaching: [
          {
            // Artwork only. Audio is deliberately absent: range requests and
            // multi-megabyte bodies do not belong in the shell cache.
            urlPattern: ({ request }) => request.destination === 'image',
            handler: 'CacheFirst',
            options: {
              cacheName: 'muzick-artwork',
              expiration: { maxEntries: 300, maxAgeSeconds: 60 * 60 * 24 * 30 },
              cacheableResponse: { statuses: [0, 200] },
            },
          },
        ],
      },
    }),
  ],
  test: {
    environment: 'jsdom',
    setupFiles: './src/test/setup.ts',
    clearMocks: true,
  },
  server: {
    proxy: {
      // ponytail: the deployed nginx injects the Authorization header, so dev can
      // point at it (DEV_API_TARGET=http://localhost:5174) instead of a bare backend.
      '/api': process.env.DEV_API_TARGET || 'http://localhost:3000',
    }
  },
  build: {
    outDir: 'dist',
    emptyOutDir: true,
    rollupOptions: {
      output: {
        // The framework changes on an npm upgrade, the app changes every
        // deploy. Splitting them means a redeploy re-downloads app code only,
        // which matters here because the service worker precaches the lot.
        manualChunks: {
          vendor: ['react', 'react-dom', '@tanstack/react-router', '@tanstack/react-query'],
        },
      },
    },
  }
})
