import { describe, expect, it } from 'vitest';
import type { RepoSummary, SessionSummary, WorktreeSummary } from '@arboretum/shared';
import { Store } from '../src/state/store.js';

function repo(id: string): RepoSummary {
  return {
    id,
    path: `/code/${id}`,
    label: id,
    defaultBranch: 'main',
    postCreateHooks: [],
    preTrust: false,
    createdAt: '2026-01-01T00:00:00Z',
    valid: true,
    hidden: false,
  };
}

function worktree(repoId: string, path: string, branch: string): WorktreeSummary {
  return {
    repoId,
    path,
    branch,
    head: 'abcdef0',
    detached: false,
    locked: false,
    prunable: false,
    isMain: branch === 'main',
    git: { ahead: 0, behind: 0, dirtyCount: 0, upstream: null },
    sessions: [],
  };
}

function session(id: string, cwd: string, over: Partial<SessionSummary> = {}): SessionSummary {
  return {
    id,
    cwd,
    command: 'claude',
    title: null,
    status: 'running',
    live: true,
    createdAt: '2026-01-01T00:00:00Z',
    endedAt: null,
    exitCode: null,
    clients: 0,
    source: 'managed',
    claudeSessionId: null,
    pid: 123,
    resumable: false,
    attachable: true,
    registryStatus: null,
    ...over,
  };
}

describe('Store', () => {
  it('corrèle les sessions au worktree par cwd et filtre les externes', () => {
    const store = new Store();
    store.applyWorktree({ type: 'repo_update', repo: repo('app') });
    store.applyWorktree({ type: 'worktree_update', repoId: 'app', worktree: worktree('app', '/code/app', 'main') });

    store.applySession({ type: 'session_update', session: session('s1', '/code/app') });
    store.applySession({ type: 'session_update', session: session('s2', '/code/app', { source: 'discovered' }) });

    // externes masquées par défaut
    expect(store.sessionsForWorktree('/code/app').map((s) => s.id)).toEqual(['s1']);
    store.setShowExternalSessions(true);
    expect(store.sessionsForWorktree('/code/app').map((s) => s.id).sort()).toEqual(['s1', 's2']);
  });

  it('liste les repos visibles, triés', () => {
    const store = new Store();
    store.applyWorktree({ type: 'repo_update', repo: { ...repo('b'), label: 'beta' } });
    store.applyWorktree({ type: 'repo_update', repo: { ...repo('a'), label: 'alpha' } });
    store.applyWorktree({ type: 'repo_update', repo: { ...repo('h'), label: 'hidden', hidden: true } });
    expect(store.listRepos().map((r) => r.label)).toEqual(['alpha', 'beta']);
  });

  it('session_exit marque la session morte', () => {
    const store = new Store();
    store.applySession({ type: 'session_update', session: session('s1', '/x') });
    store.applySession({ type: 'session_exit', sessionId: 's1', exitCode: 0, signal: null });
    expect(store.getSession('s1')?.live).toBe(false);
    expect(store.getSession('s1')?.status).toBe('exited');
  });

  it('waitingSessions ne retient que les sessions live en attente', () => {
    const store = new Store();
    store.applySession({ type: 'session_update', session: session('s1', '/x', { activity: 'waiting' }) });
    store.applySession({ type: 'session_update', session: session('s2', '/y', { activity: 'busy' }) });
    store.applySession({ type: 'session_update', session: session('s3', '/z', { activity: 'waiting', live: false, status: 'exited' }) });
    expect(store.waitingSessions().map((s) => s.id)).toEqual(['s1']);
  });

  it('worktree_removed retire le worktree', () => {
    const store = new Store();
    store.applyWorktree({ type: 'repo_update', repo: repo('app') });
    store.applyWorktree({ type: 'worktree_update', repoId: 'app', worktree: worktree('app', '/code/app-wt', 'feat') });
    expect(store.listWorktrees('app')).toHaveLength(1);
    store.applyWorktree({ type: 'worktree_removed', repoId: 'app', path: '/code/app-wt' });
    expect(store.listWorktrees('app')).toHaveLength(0);
  });
});
