// @vitest-environment node

import type { ConfigEnv, UserConfig, UserConfigFn } from 'vite';

import { spawnSync } from 'node:child_process';
import { readFileSync, unlinkSync, writeFileSync } from 'node:fs';
import { resolve } from 'node:path';
import process from 'node:process';

import { afterEach, beforeEach, describe, expect, it } from 'vitest';

import config from '../vite.config';

const developmentEnvironmentNames = [
  'ONLYOFFICE_DOCS_URL',
  'ONLYOFFICE_PLUGIN_DEV_HOST',
  'ONLYOFFICE_PLUGIN_DEV_PORT',
  'ONLYOFFICE_PLUGIN_HMR_CLIENT_PORT',
  'ONLYOFFICE_PLUGIN_HMR_HOST',
  'ONLYOFFICE_PLUGIN_HMR_PROTOCOL',
  'ONLYOFFICE_PLUGIN_PUBLIC_HOST',
] as const;
const originalEnvironment = Object.fromEntries(developmentEnvironmentNames.map((name) => [name, process.env[name]]));
const pluginRoot = process.cwd();
const repositoryRoot = resolve(pluginRoot, '../../..');
const testEnvironmentPath = resolve(pluginRoot, '.env.task4-test.local');

function resolveConfig(command: ConfigEnv['command'], mode = command === 'serve' ? 'development' : 'production'): UserConfig {
  expect(config).toBeTypeOf('function');
  const resolved = (config as UserConfigFn)({
    command,
    isPreview: false,
    isSsrBuild: false,
    mode,
  });
  if (resolved instanceof Promise) throw new Error('测试要求 Vite 配置同步解析');
  return resolved;
}

describe('vite config', () => {
  beforeEach(() => {
    for (const name of developmentEnvironmentNames) delete process.env[name];
  });

  afterEach(() => {
    try {
      unlinkSync(testEnvironmentPath);
    } catch (error) {
      if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error;
    }
    for (const name of developmentEnvironmentNames) {
      const value = originalEnvironment[name];
      if (value === undefined) delete process.env[name];
      else process.env[name] = value;
    }
  });

  it('从 mode local env 加载 ONLYOFFICE 配置且 shell 环境优先', () => {
    writeFileSync(
      testEnvironmentPath,
      [
        'ONLYOFFICE_PLUGIN_DEV_HOST=127.0.0.1',
        'ONLYOFFICE_PLUGIN_DEV_PORT=4311',
        'ONLYOFFICE_PLUGIN_PUBLIC_HOST=env-file.example.com',
        'ONLYOFFICE_PLUGIN_HMR_HOST=hmr.env-file.example.com',
        'UNRELATED_BROWSER_SECRET=must-not-be-injected',
      ].join('\n'),
    );
    process.env.ONLYOFFICE_PLUGIN_DEV_PORT = '4312';

    const serveConfig = resolveConfig('serve', 'task4-test');

    expect(serveConfig.server).toMatchObject({
      hmr: { clientPort: 4312, host: 'hmr.env-file.example.com' },
      host: '127.0.0.1',
      port: 4312,
    });
    expect(serveConfig.define).toBeUndefined();
  });

  it('serve 使用固定开发 release、端口和浏览器可访问的 HMR 配置', () => {
    const serveConfig = resolveConfig('serve');

    expect(serveConfig.base).toBe('/onlyoffice-plugins/0.1.0-dev/eln-template-filler/');
    expect(serveConfig.server).toMatchObject({
      hmr: { clientPort: 4173, host: 'localhost', protocol: 'ws' },
      host: '0.0.0.0',
      port: 4173,
      strictPort: true,
    });
    expect(serveConfig.plugins).toEqual(expect.arrayContaining([expect.objectContaining({ name: 'onlyoffice-development' })]));
  });

  it('build 保持正式相对资源路径、生产资产和入口语义', () => {
    const buildConfig = resolveConfig('build');

    expect(buildConfig.base).toBe('./');
    expect(buildConfig.server).toBeUndefined();
    expect(buildConfig.build?.sourcemap).toBe(false);
    expect(buildConfig.build?.rollupOptions?.input).toBe(resolve(process.cwd(), 'index.html'));
    expect(buildConfig.plugins).toEqual(expect.arrayContaining([expect.objectContaining({ name: 'eln-production-assets' })]));
  });

  it('包级 dev 脚本由根 turbo-run 选择器发现', () => {
    const packageJson = JSON.parse(readFileSync(resolve(process.cwd(), 'package.json'), 'utf8')) as {
      scripts: Record<string, string>;
      version: string;
    };
    const turboJson = JSON.parse(readFileSync(resolve(process.cwd(), '../../../turbo.json'), 'utf8')) as {
      tasks: Record<string, Record<string, unknown>>;
    };

    expect(packageJson.version).toBe('0.1.0');
    expect(packageJson.scripts.dev).toBe('vite');
    expect(turboJson.tasks.dev).toMatchObject({ cache: false, persistent: true });

    const discovery = spawnSync(
      'pnpm',
      [
        'exec',
        'node',
        '--input-type=module',
        '-e',
        "import { getPackages } from '@vben/node-utils'; const { packages } = await getPackages(); console.log(packages.filter((pkg) => pkg.packageJson.scripts?.dev).map((pkg) => pkg.packageJson.name).includes('onlyoffice-eln-template-filler'));",
      ],
      { cwd: resolve(repositoryRoot, 'scripts/turbo-run'), encoding: 'utf8' },
    );
    expect(discovery.status, discovery.stderr).toBe(0);
    expect(discovery.stdout.trim()).toBe('true');
  });
});
