import { defineConfig, loadEnv, Plugin } from 'vite';
import react from '@vitejs/plugin-react';
import { createHtmlPlugin } from 'vite-plugin-html';
import type { IncomingMessage, ServerResponse } from 'http';
import * as fs from 'fs';
import * as path from 'path';

type I18nEntry = { context: string; key: string; value: string };

/** Find the nearest enclosing function/component name above a given character offset. */
function _findEnclosingComponent(content: string, charOffset: number): string {
  const reFunc = /(?:export\s+)?(?:const|function)\s+([A-Z_]\w*)/g;
  let best = '';
  let m: RegExpExecArray | null;
  while ((m = reFunc.exec(content)) !== null) {
    if (m.index > charOffset) break;
    best = m[1];
  }
  return best;
}

/** Scan all .ts/.tsx under srcRoot for t() calls and return structured entries with context. */
function _scanTKeys(srcRoot: string): I18nEntry[] {
  const keyMap = new Map<string, Set<string>>();
  const reSingle = /\bt\(\s*'((?:\\.|[^'])+)'\s*(?:,|\))/g;
  const reDouble = /\bt\(\s*"((?:\\.|[^"])+)"\s*(?:,|\))/g;

  const _addKey = (key: string, relFile: string, content: string, offset: number): void => {
    const comp = _findEnclosingComponent(content, offset);
    const ctx = comp ? `${relFile} > ${comp}` : relFile;
    if (!keyMap.has(key)) keyMap.set(key, new Set());
    keyMap.get(key)!.add(ctx);
  };

  const walk = (dir: string): void => {
    if (!fs.existsSync(dir)) return;
    for (const ent of fs.readdirSync(dir, { withFileTypes: true })) {
      const full = path.join(dir, ent.name);
      if (ent.isDirectory()) {
        walk(full);
      } else if (/\.(tsx?)$/i.test(ent.name)) {
        const content = fs.readFileSync(full, 'utf-8');
        const relFile = path.relative(srcRoot, full).replace(/\\/g, '/');
        let m: RegExpExecArray | null;
        reSingle.lastIndex = 0;
        while ((m = reSingle.exec(content)) !== null) {
          const raw = m[1].replace(/\\'/g, "'").replace(/\\\\/g, '\\');
          if (raw) _addKey(raw, relFile, content, m.index);
        }
        reDouble.lastIndex = 0;
        while ((m = reDouble.exec(content)) !== null) {
          const raw = m[1].replace(/\\"/g, '"').replace(/\\\\/g, '\\');
          if (raw) _addKey(raw, relFile, content, m.index);
        }
      }
    }
  };
  walk(srcRoot);

  const entries: I18nEntry[] = [];
  for (const [key, contexts] of [...keyMap.entries()].sort((a, b) => a[0].localeCompare(b[0], 'de'))) {
    entries.push({ context: 'ui', key, value: [...contexts].sort().join(' | ') });
  }
  return entries;
}

function extractI18nKeys(): Plugin {
  return {
    name: 'extract-i18n-keys',
    configureServer(server) {
      server.middlewares.use((req: IncomingMessage, res: ServerResponse, next: () => void) => {
        const url = req.url?.split('?')[0] ?? '';
        if (!url.endsWith('/i18n-keys.json')) {
          next();
          return;
        }
        const srcDir = path.join(process.cwd(), 'src');
        const payload = JSON.stringify(_scanTKeys(srcDir), null, 2);
        res.setHeader('Content-Type', 'application/json; charset=utf-8');
        res.end(payload);
      });
    },
    writeBundle(options) {
      const outDir = options.dir ?? path.resolve(process.cwd(), 'dist');
      const srcDir = path.join(process.cwd(), 'src');
      const entries = _scanTKeys(srcDir);
      if (!fs.existsSync(outDir)) {
        fs.mkdirSync(outDir, { recursive: true });
      }
      fs.writeFileSync(path.join(outDir, 'i18n-keys.json'), `${JSON.stringify(entries)}\n`, 'utf-8');
    },
  };
}

// Custom plugin to serve static HTML files from public directory BEFORE SPA fallback
function serveStaticHtml(): Plugin {
  return {
    name: 'serve-static-html',
    enforce: 'pre',
    configureServer(server) {
      // Directly adding middleware runs BEFORE internal Vite middlewares
      server.middlewares.use((req, res, next) => {
        // Check if request is for a static HTML file in public
        const url = req.url?.split('?')[0]; // Remove query string
        if (url && url.endsWith('.html') && url !== '/' && url !== '/index.html') {
          const filePath = path.join(process.cwd(), 'public', url);
          if (fs.existsSync(filePath)) {
            res.setHeader('Content-Type', 'text/html; charset=utf-8');
            res.statusCode = 200;
            res.end(fs.readFileSync(filePath, 'utf-8'));
            return;
          }
        }
        next();
      });
    },
  };
}

export default defineConfig(({ mode }) => {
  // Load env file based on mode
  const env = loadEnv(mode, process.cwd(), '');
  
  return {
    plugins: [
      // Serve static HTML files
      serveStaticHtml(),
      extractI18nKeys(),
      react(),
      createHtmlPlugin({
        // Only process main index.html, not public static files
        pages: [
          {
            entry: 'src/main.tsx',
            filename: 'index.html',
            template: 'index.html',
            injectOptions: {
              data: {
                VITE_APP_NAME: env.VITE_APP_NAME || 'PowerOn',
              },
            },
          },
        ],
      }),
    ],
    envPrefix: 'VITE_',
    css: {
      modules: {
        scopeBehaviour: 'local',  // Default behavior for CSS modules
      },
    },
    // Ensure public files are served correctly as static
    publicDir: 'public',
  };
});
