import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import { mkdtempSync, rmSync } from 'fs';
import { tmpdir } from 'os';
import { join } from 'path';
import { Repository } from './db/repository.js';
import { BrowserSessionRepo } from './db/browser-session-repo.js';
import { inheritJobContext } from './worker.js';

// Regression: a job that DESCENDS from another (subtask spawn, subtask ASK
// re-enqueue) must inherit the parent's bound browser session profile. Without
// it, BrowseWeb inside the derived job runs without the saved login session
// (cookies/storageState are only loaded when the job row carries the profile
// id). research-via-delegate made nearly all browsing happen inside subtasks,
// so the missing inheritance meant "BrowseWeb stopped using the saved session".
describe('inheritJobContext (derived-job session inheritance)', () => {
  let dir: string;
  let repo: Repository;

  beforeEach(() => {
    dir = mkdtempSync(join(tmpdir(), 'inherit-jobctx-'));
    repo = new Repository(join(dir, 'db.sqlite'));
    // browser_session_profiles.owner_id REFERENCES users(id) (FK ON), so the
    // owner must exist before a profile row can be inserted.
    repo.getDb().prepare(
      `INSERT INTO users (id, email, role, status, created_at, updated_at)
       VALUES ('u-1', 'u1@example.com', 'user', 'active', 0, 0)`,
    ).run();
  });
  afterEach(() => {
    repo.close?.();
    rmSync(dir, { recursive: true, force: true });
  });

  it('carries the parent job browserSessionProfileId', async () => {
    const sess = new BrowserSessionRepo(repo.getDb());
    const profileId = sess.createProfile({
      ownerId: 'u-1', label: 'github', startUrl: 'https://github.com',
      matchPatterns: ['github.com'], storageOrigins: ['https://github.com'],
      loginUrlPatterns: ['https://github.com/login'],
    });
    const parent = await repo.createJob({
      repo: 'local/task-1', issueNumber: 1, instruction: 'x', pieceName: 'general',
      ownerId: 'u-1', browserSessionProfileId: profileId,
    } as never);

    expect(inheritJobContext(parent).browserSessionProfileId).toBe(profileId);
  });

  it('returns null when the parent has no bound profile', async () => {
    const parent = await repo.createJob({
      repo: 'local/task-2', issueNumber: 2, instruction: 'x', pieceName: 'general',
      ownerId: 'u-1',
    } as never);
    expect(inheritJobContext(parent).browserSessionProfileId).toBeNull();
  });

  it('also carries ownership, visibility and space', async () => {
    const parent = await repo.createJob({
      repo: 'local/task-3', issueNumber: 3, instruction: 'x', pieceName: 'general',
      ownerId: 'u-7', visibility: 'org', visibilityScopeOrgId: 'org-9', spaceId: 'case-42',
    } as never);
    expect(inheritJobContext(parent)).toEqual({
      ownerId: 'u-7',
      visibility: 'org',
      visibilityScopeOrgId: 'org-9',
      spaceId: 'case-42',
      browserSessionProfileId: null,
    });
  });

  // The actual bug: a derived job built by spreading inheritJobContext(parent)
  // must PERSIST the profile id on its own row (so the worker decrypts and
  // injects the saved session when it later runs).
  it('a derived job spreading inheritJobContext persists the bound profile', async () => {
    const sess = new BrowserSessionRepo(repo.getDb());
    const profileId = sess.createProfile({
      ownerId: 'u-1', label: 'x', startUrl: 'https://x.com',
      matchPatterns: ['x.com'], storageOrigins: ['https://x.com'],
      loginUrlPatterns: ['https://x.com/login'],
    });
    const parent = await repo.createJob({
      repo: 'local/task-4', issueNumber: 4, instruction: 'parent', pieceName: 'general',
      ownerId: 'u-1', browserSessionProfileId: profileId,
    } as never);

    // Mirror worker.ts subtask spawn: spread the inherited context.
    const sub = await repo.createJob({
      repo: `subtask/${parent.id}`, issueNumber: 0, instruction: 'child',
      pieceName: 'general', parentJobId: parent.id, subtaskDepth: 1,
      ...inheritJobContext(parent),
    } as never);

    const reloaded = await repo.getJob(sub.id);
    expect(reloaded?.browserSessionProfileId).toBe(profileId);
  });
});
