import { existsSync } from 'node:fs';
import { mkdtemp, mkdir, readFile, rm, writeFile } from 'node:fs/promises';
import os from 'node:os';
import path from 'node:path';

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

import {
  getSearchTaskRuntimePaths,
  prepareSearchTaskRuntimeProfile,
  syncSearchTaskRuntimeProfileToAccount,
} from './search-profile-workspace.ts';

const tempDirs: string[] = [];

async function makeTempRoot() {
  const dir = await mkdtemp(path.join(os.tmpdir(), 'search-profile-workspace-'));
  tempDirs.push(dir);
  return dir;
}

afterEach(async () => {
  await Promise.all(tempDirs.splice(0).map((dir) => rm(dir, { recursive: true, force: true })));
});

describe('search profile workspace', () => {
  it('copies an existing account profile into an empty task runtime profile', async () => {
    const runtimeRootDir = await makeTempRoot();
    const accountProfileDir = path.join(runtimeRootDir, 'account-profile');
    await mkdir(path.join(accountProfileDir, 'Default'), { recursive: true });
    await writeFile(path.join(accountProfileDir, 'Default', 'Cookies'), 'account-cookie', 'utf8');

    const runtimePaths = await prepareSearchTaskRuntimeProfile({
      taskId: 'task-001',
      accountProfileDir,
      runtimeRootDir,
    });

    await expect(readFile(path.join(runtimePaths.profileDir, 'Default', 'Cookies'), 'utf8'))
      .resolves.toBe('account-cookie');
  });

  it('does not overwrite a non-empty task runtime profile when resuming', async () => {
    const runtimeRootDir = await makeTempRoot();
    const accountProfileDir = path.join(runtimeRootDir, 'account-profile');
    const runtimePaths = getSearchTaskRuntimePaths('task-002', runtimeRootDir);
    await mkdir(path.join(accountProfileDir, 'Default'), { recursive: true });
    await mkdir(path.join(runtimePaths.profileDir, 'Default'), { recursive: true });
    await writeFile(path.join(accountProfileDir, 'Default', 'Cookies'), 'account-cookie', 'utf8');
    await writeFile(path.join(runtimePaths.profileDir, 'Default', 'Cookies'), 'runtime-cookie', 'utf8');

    await prepareSearchTaskRuntimeProfile({
      taskId: 'task-002',
      accountProfileDir,
      runtimeRootDir,
    });

    await expect(readFile(path.join(runtimePaths.profileDir, 'Default', 'Cookies'), 'utf8'))
      .resolves.toBe('runtime-cookie');
  });

  it('syncs task runtime profile changes back to the account profile', async () => {
    const runtimeRootDir = await makeTempRoot();
    const accountProfileDir = path.join(runtimeRootDir, 'account-profile');
    const runtimePaths = getSearchTaskRuntimePaths('task-003', runtimeRootDir);
    await mkdir(path.join(accountProfileDir, 'Default'), { recursive: true });
    await mkdir(path.join(runtimePaths.profileDir, 'Default'), { recursive: true });
    await writeFile(path.join(accountProfileDir, 'Default', 'Cookies'), 'old-cookie', 'utf8');
    await writeFile(path.join(runtimePaths.profileDir, 'Default', 'Cookies'), 'new-cookie', 'utf8');

    await syncSearchTaskRuntimeProfileToAccount({
      taskId: 'task-003',
      accountProfileDir,
      runtimeRootDir,
    });

    await expect(readFile(path.join(accountProfileDir, 'Default', 'Cookies'), 'utf8'))
      .resolves.toBe('new-cookie');
  });

  it('strips volatile Chrome Singleton files during copy and sync', async () => {
    const runtimeRootDir = await makeTempRoot();
    const accountProfileDir = path.join(runtimeRootDir, 'account-profile');
    await mkdir(accountProfileDir, { recursive: true });
    await writeFile(path.join(accountProfileDir, 'SingletonLock'), 'lock', 'utf8');
    await writeFile(path.join(accountProfileDir, 'Preferences'), '{}', 'utf8');

    const runtimePaths = await prepareSearchTaskRuntimeProfile({
      taskId: 'task-004',
      accountProfileDir,
      runtimeRootDir,
    });

    expect(existsSync(path.join(runtimePaths.profileDir, 'SingletonLock'))).toBe(false);

    await writeFile(path.join(runtimePaths.profileDir, 'SingletonSocket'), 'socket', 'utf8');
    await syncSearchTaskRuntimeProfileToAccount({
      taskId: 'task-004',
      accountProfileDir,
      runtimeRootDir,
    });

    expect(existsSync(path.join(accountProfileDir, 'SingletonLock'))).toBe(false);
    expect(existsSync(path.join(accountProfileDir, 'SingletonSocket'))).toBe(false);
  });
});
