import { defineConfig } from 'vite'
import { readFileSync } from 'fs'
import { basename } from 'path'
import { transpile } from 'typescript'
import { minify } from 'html-minifier-next'
import preact from '@preact/preset-vite'

const appConfig = JSON.parse(readFileSync('tsconfig.app.json', 'utf8'))

export default defineConfig({
    build: {
        assetsInlineLimit: 999_999_999,
        cssMinify: 'esbuild',
        minify: 'esbuild',
        outDir: 'dist',
        rollupOptions: {
            input: {
                index: 'index.html',
                embed: 'embed.html',
            },
            output: {
                hashCharacters: 'hex',
                entryFileNames: 'assets/[name].[hash].js',
                chunkFileNames: 'assets/[name].[hash].js',
                assetFileNames: 'assets/[name].[hash][extname]',
            },
        },
    },
    server: {
        strictPort: true,
        port: 5173,
        proxy: {
            '/api': {
                // cd backend && go run main.go
                target: 'http://localhost:8080',
                changeOrigin: true,
                rewrite: (path) => path.replace('/api', ''),
            },
            '/cdn': {
                // npx serve -C ./backend/_public
                target: 'http://localhost:3000',
                changeOrigin: true,
                rewrite: (path) => path.replace('/cdn', ''),
            },
        },
    },
    plugins: [
        preact(),
        {
            name: 'html-template',
            transformIndexHtml(html, ctx) {
                return html
                    .replaceAll(/{{ include-env }}/g, () => {
                        return `<script>
                                window.__ENV__ = {
                                    CDN: "${ctx.server ? '/cdn' : 'https://cdn.gifuu.pancakz.net'}",
                                    API: "${ctx.server ? '/api' : 'https://api.gifuu.pancakz.net'}",
                                    WEB: "${ctx.server ? '' : 'https://gifuu.pancakz.net'}",
                                }
                            </script>`
                    })
                    .replaceAll(/{{ include-b64 '(.*?)' '(.*?)' }}/g, (_, mime: string, filepath: string) => {
                        const content = readFileSync(filepath, 'base64')
                        const inlined = `data:${mime};base64,${content}`

                        this.warn(`Embedding 'base64' from '${filepath}'`)
                        return inlined
                    })
                    .replaceAll(/{{ include-tag '(.*?)' '(.*?)' }}/g, (_, tag: string, filepath: string) => {
                        let content = readFileSync(filepath, 'utf8')

                        if (tag === 'script' && filepath.endsWith('.ts')) {
                            content = transpile(content, appConfig)
                            this.warn(`Transpiled inline script : ${basename(filepath)}`)
                        }

                        const inlined = `<${tag}>\n${content}</${tag}>`

                        this.warn(`Embedding '${tag}' from '${filepath}'`)
                        return inlined
                    })
                    .replaceAll(/{{ include-article '(.*?)' '(.*?)' }}/g, (_, id: string, filepath: string) => {
                        const content = readFileSync(filepath, 'utf8').replaceAll(
                            /<pre([^>]*)>\s*\n([\s\S]*?)<\/pre>/g,
                            (_, attributes, inner) => {
                                const lines = inner.split('\n')
                                const indent = lines[0].match(/^(\s*)/)?.[1].length ?? 0
                                const trimmed = lines
                                    .map((l: string) => l.slice(indent))
                                    .join('\n')
                                    .trim()
                                return `<pre${attributes}>${trimmed}</pre>`
                            },
                        )
                        const inlined = `<template class="article" id="${id}">\n${content}</template>`

                        this.warn(`Embedding article '${id}' from '${filepath}'`)
                        return inlined
                    })
            },
        },
        {
            name: 'html-minify',
            transformIndexHtml(html, ctx) {
                if (ctx.server) return html // skip dev mode
                this.warn(`Minifying Document: ${basename(ctx.filename)}`)

                return minify(html, {
                    collapseWhitespace: true,
                    removeComments: true,
                    minifyCSS: true,
                    minifyJS: true,
                })
            },
        },
    ],
})
