import { readFileSync } from 'node:fs';
import { connect } from 'node:net';
import type { AddressInfo } from 'node:net';
import { enhancedImages } from '@sveltejs/enhanced-img';
import { sveltekit } from '@sveltejs/kit/vite';
import { svelteTesting } from '@testing-library/svelte/vite';
import { defineConfig } from 'vitest/config';
import { createLogger, type Plugin, type ProxyOptions } from 'vite';

const packageJson = JSON.parse(readFileSync(new URL('./package.json', import.meta.url), 'utf8')) as {
  name: string;
  version: string;
  devDependencies?: Record<string, string>;
};

const appName = packageJson.name;
const appVersion = packageJson.version;
const viteVersion = packageJson.devDependencies?.vite ?? 'unknown';
const svelteKitVersion = packageJson.devDependencies?.['@sveltejs/kit'] ?? 'unknown';
const submitProxyTarget = 'http://localhost:8000';
const proxyRoutes = {
  '/api/submit': '/submit',
  '/api/onboarding-submit': '/onboarding-submit',
  '/api/contract-submit': '/contract-submit',
} as const;
const submitProxyPath = '/api/submit';
const submitProxyDestination = `${submitProxyTarget}${proxyRoutes[submitProxyPath]}`;

function resolvePort(target: URL) {
  if (target.port) {
    return Number(target.port);
  }

  return target.protocol === 'https:' ? 443 : 80;
}

function probeTcpPort(target: string, timeoutMs = 1200) {
  const url = new URL(target);

  return new Promise<{ ok: true } | { ok: false; error: NodeJS.ErrnoException }>((resolve) => {
    const socket = connect({
      host: url.hostname,
      port: resolvePort(url)
    });

    let settled = false;

    const finish = (result: { ok: true } | { ok: false; error: NodeJS.ErrnoException }) => {
      if (settled) {
        return;
      }

      settled = true;
      socket.destroy();
      resolve(result);
    };

    socket.once('connect', () => finish({ ok: true }));
    socket.once('error', (error: NodeJS.ErrnoException) => finish({ ok: false, error }));
    socket.setTimeout(timeoutMs, () =>
      finish({
        ok: false,
        error: Object.assign(new Error(`Timed out after ${timeoutMs}ms`), { code: 'ETIMEDOUT' })
      })
    );
  });
}

function formatProxyError(error: NodeJS.ErrnoException) {
  const code = error.code ?? 'UNKNOWN';
  const hint =
    code === 'ECONNREFUSED'
      ? `Mail API is not reachable at ${submitProxyTarget}. Start the Python API before submitting the form.`
      : code === 'ETIMEDOUT'
        ? `Mail API at ${submitProxyTarget} did not respond in time.`
        : 'The booking request could not be forwarded to the Mail API.';

  return {
    code,
    hint
  };
}

function createGoodwalkLogger() {
  const logger = createLogger();
  const baseError = logger.error.bind(logger);

  logger.error = (msg, options) => {
    if (
      typeof msg === 'string' &&
      msg.includes('[vite] http proxy error') &&
      (msg.includes('/submit') || msg.includes('/onboarding-submit') || msg.includes('/contract-submit'))
    ) {
      return;
    }

    baseError(msg, options);
  };

  return logger;
}

function goodwalkDevServerPlugin(logger: ReturnType<typeof createLogger>): Plugin {
  let printedStartup = false;

  const printStartup = async (serverHost: string | undefined, address: AddressInfo | string | null) => {
    if (printedStartup) {
      return;
    }

    printedStartup = true;

    const localUrls = server.resolvedUrls?.local ?? [];
    const networkUrls = server.resolvedUrls?.network ?? [];
    const reachable = await probeTcpPort(submitProxyTarget);
    const backendStatus = reachable.ok
      ? `ready at ${submitProxyTarget}`
      : `${formatProxyError(reachable.error).code} at ${submitProxyTarget}`;

    logger.info('');
    logger.info(`[goodwalk] ${appName} dev server ready`);
    logger.info(`[goodwalk] Version ${appVersion} | Node ${process.version} | Vite ${viteVersion} | SvelteKit ${svelteKitVersion}`);

    if (localUrls.length) {
      logger.info(`[goodwalk] Local: ${localUrls.join(', ')}`);
    }

    if (networkUrls.length) {
      logger.info(`[goodwalk] Network: ${networkUrls.join(', ')}`);
    }

    if (!localUrls.length && address && typeof address !== 'string') {
      const host = serverHost && serverHost !== '0.0.0.0' ? serverHost : 'localhost';
      logger.info(`[goodwalk] Local: http://${host}:${address.port}/`);
    }

    logger.info(`[goodwalk] Booking proxy: ${submitProxyPath} -> ${submitProxyDestination}`);

    if (reachable.ok) {
      logger.info(`[goodwalk] Mail API: ${backendStatus}`);
    } else {
      logger.warn(`[goodwalk] Mail API: ${backendStatus}`);
      logger.warn(`[goodwalk] Hint: ${formatProxyError(reachable.error).hint}`);
    }

    logger.info('');
  };

  let server: import('vite').ViteDevServer;

  return {
    name: 'goodwalk-dev-server-logging',
    configureServer(devServer) {
      server = devServer;

      devServer.httpServer?.once('listening', () => {
        const address = devServer.httpServer?.address() ?? null;
        const configuredHost =
          typeof devServer.config.server.host === 'string' ? devServer.config.server.host : undefined;

        void printStartup(configuredHost, address);
      });
    }
  };
}

export default defineConfig(() => {
  const logger = createGoodwalkLogger();

  const createMailProxy = (apiPath: keyof typeof proxyRoutes): ProxyOptions => ({
    target: submitProxyTarget,
    rewrite: (path) => path.replace(apiPath, proxyRoutes[apiPath]),
    configure(proxy) {
      proxy.on('error', (error: NodeJS.ErrnoException, req, res) => {
        const { code, hint } = formatProxyError(error);
        const requestPath = req.url ?? apiPath;
        const requestMethod = req.method ?? 'POST';
        const targetPath = `${submitProxyTarget}${proxyRoutes[apiPath]}`;

        logger.error(
          [
            '',
            '[goodwalk] Mail proxy failed',
            `[goodwalk] Request: ${requestMethod} ${requestPath}`,
            `[goodwalk] Target: ${targetPath}`,
            `[goodwalk] Code: ${code}`,
            `[goodwalk] Message: ${error.message}`,
            `[goodwalk] Hint: ${hint}`,
            ''
          ].join('\n')
        );

        if (res && 'writeHead' in res && !res.headersSent) {
          res.writeHead(502, { 'Content-Type': 'application/json' });
          res.end(
            JSON.stringify({
              error: 'Mail API unavailable',
              detail: hint
            })
          );
        }
      });
    }
  });

  return {
    customLogger: logger,
    plugins: [goodwalkDevServerPlugin(logger), enhancedImages(), svelteTesting({ autoCleanup: false }), sveltekit()],
    server: {
      proxy: {
        '/api/submit': createMailProxy('/api/submit'),
        '/api/onboarding-submit': createMailProxy('/api/onboarding-submit'),
        '/api/contract-submit': createMailProxy('/api/contract-submit'),
        '/api/auth': {
          target: submitProxyTarget,
          rewrite: (path) => path.replace('/api/auth', '/auth'),
        },
        '/api/save-draft': {
          target: submitProxyTarget,
          rewrite: (path) => path.replace('/api/save-draft', '/auth/save-draft'),
        },
      }
    },
    test: {
      environment: 'jsdom',
      setupFiles: ['./vitest.setup.ts'],
      include: ['src/**/*.test.ts']
    }
  };
});
