/**
 * End-to-end: a local-org member sees 'org'-scoped resources; a non-member
 * does not. Validates the whole chain — local org membership → resolveOrgIds
 * → session.orgIds → the provider-agnostic buildVisibilityWhere.
 *
 * See docs/superpowers/plans/2026-06-09-local-orgs.md.
 */
import { afterEach, beforeEach, describe, it, expect } from 'vitest';
import { mkdtempSync, rmSync } from 'fs';
import { join } from 'path';
import { tmpdir } from 'os';
import { Repository } from '../db/repository.js';
import { runMigrations } from '../db/migrate.js';
import { resolveOrgIds } from './auth.js';

function viewer(id: string, orgIds: string[]): Express.User {
  return {
    id, email: `${id}@x.com`, name: id, avatarUrl: null,
    role: 'user', status: 'active', orgIds,
    defaultVisibility: 'private', defaultVisibilityOrgId: null,
  };
}

describe('local orgs — org visibility E2E', () => {
  let tempDir = '';
  let repo: Repository;

  beforeEach(() => {
    tempDir = mkdtempSync(join(tmpdir(), 'maestro-orgvis-'));
    repo = new Repository(join(tempDir, 'orchestrator.db'));
    runMigrations(repo.getDb());
  });
  afterEach(() => {
    repo.close();
    if (tempDir) { rmSync(tempDir, { recursive: true, force: true }); tempDir = ''; }
  });

  it('resolveOrgIds includes the local orgs a user belongs to', () => {
    const alice = repo.createUser({ email: 'a@x.com', name: 'A', role: 'user', status: 'active' }).id;
    const org = repo.createLocalOrg('Team', alice);
    repo.addOrgMember(org.id, alice);
    expect(resolveOrgIds(repo, alice)).toContain(org.id);
  });

  it('an org member sees an org-scoped task; a non-member does not', async () => {
    const carol = repo.createUser({ email: 'carol@x.com', name: 'Carol', role: 'user', status: 'active' }).id;
    const alice = repo.createUser({ email: 'alice@x.com', name: 'Alice', role: 'user', status: 'active' }).id;
    const bob = repo.createUser({ email: 'bob@x.com', name: 'Bob', role: 'user', status: 'active' }).id;
    const org = repo.createLocalOrg('Team', carol);
    repo.addOrgMember(org.id, carol);
    repo.addOrgMember(org.id, alice); // alice is a member, bob is not

    await repo.createLocalTask({
      title: 'org task', body: 'b', ownerId: carol,
      visibility: 'org', visibilityScopeOrgId: org.id,
    });

    const aliceTasks = await repo.listLocalTasks({ viewer: viewer(alice, resolveOrgIds(repo, alice)) });
    const bobTasks = await repo.listLocalTasks({ viewer: viewer(bob, resolveOrgIds(repo, bob)) });

    expect(aliceTasks.some(t => t.title === 'org task')).toBe(true);  // member sees it
    expect(bobTasks.some(t => t.title === 'org task')).toBe(false);   // non-member does not
  });

  it('the org name resolves on display after the COALESCE extension', async () => {
    const carol = repo.createUser({ email: 'c@x.com', name: 'C', role: 'user', status: 'active' }).id;
    const org = repo.createLocalOrg('Engineering', carol);
    repo.addOrgMember(org.id, carol);
    const t = await repo.createLocalTask({
      title: 'x', body: 'b', ownerId: carol, visibility: 'org', visibilityScopeOrgId: org.id,
    });
    const got = await repo.getLocalTask(t.id, { viewer: viewer(carol, resolveOrgIds(repo, carol)) });
    expect(got?.visibilityScopeOrgName).toBe('Engineering');
  });
});
