import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import { SessionStore } from './store.js';
import { SessionIndexer } from './indexer.js';
import { unlinkSync, existsSync } from 'fs';
import { join } from 'path';
import { tmpdir } from 'os';

describe('SessionStore', () => {
  const dbPath = join(tmpdir(), 'flynn-test-sessions.db');
  let store: SessionStore;

  beforeEach(() => {
    store = new SessionStore(dbPath);
  });

  afterEach(() => {
    store.close();
    if (existsSync(dbPath)) {
      unlinkSync(dbPath);
    }
  });

  it('saves and retrieves messages', () => {
    const sessionId = 'test-session';

    store.addMessage(sessionId, { role: 'user', content: 'Hello' });
    store.addMessage(sessionId, { role: 'assistant', content: 'Hi there!' });

    const messages = store.getMessages(sessionId);

    expect(messages).toHaveLength(2);
    expect(messages[0].role).toBe('user');
    expect(messages[0].content).toBe('Hello');
    expect(messages[1].role).toBe('assistant');
    expect(messages[1].content).toBe('Hi there!');
  });

  it('clears session messages', () => {
    const sessionId = 'test-session';

    store.addMessage(sessionId, { role: 'user', content: 'Hello' });
    store.clearSession(sessionId);

    const messages = store.getMessages(sessionId);
    expect(messages).toHaveLength(0);
  });

  it('handles multiple sessions independently', () => {
    store.addMessage('session-1', { role: 'user', content: 'Session 1' });
    store.addMessage('session-2', { role: 'user', content: 'Session 2' });

    expect(store.getMessages('session-1')).toHaveLength(1);
    expect(store.getMessages('session-2')).toHaveLength(1);
    expect(store.getMessages('session-1')[0].content).toBe('Session 1');
  });

  it('lists all sessions', () => {
    store.addMessage('session-a', { role: 'user', content: 'A' });
    store.addMessage('session-b', { role: 'user', content: 'B' });

    const sessions = store.listSessions();

    expect(sessions).toContain('session-a');
    expect(sessions).toContain('session-b');
  });

  it('stores and retrieves message metadata for indexed history', () => {
    const indexer = new SessionIndexer({ maxKeywords: 5 });
    const metadata = indexer.indexText('deploy backend release');
    store.addMessage('session-meta', { role: 'user', content: 'deploy backend release' }, metadata);

    const rows = store.getMessagesWithMetadata('session-meta');
    expect(rows).toHaveLength(1);
    expect(rows[0].metadata?.keywords).toContain('deploy');
  });

  describe('pairing persistence', () => {
    it('getPairingStore returns a PairingStore', () => {
      const pairingStore = store.getPairingStore();
      expect(pairingStore).toBeDefined();
      expect(pairingStore.loadApproved).toBeInstanceOf(Function);
      expect(pairingStore.saveApproved).toBeInstanceOf(Function);
      expect(pairingStore.removeApproved).toBeInstanceOf(Function);
    });

    it('saveApproved and loadApproved round-trip', () => {
      const ps = store.getPairingStore();
      ps.saveApproved({ channel: 'telegram', senderId: '123', approvedAt: 1000, codeUsed: 'AABB11' });
      ps.saveApproved({ channel: 'discord', senderId: '456', approvedAt: 2000, codeUsed: 'CC33DD' });
      const loaded = ps.loadApproved();
      expect(loaded).toHaveLength(2);
      expect(loaded).toEqual(expect.arrayContaining([
        expect.objectContaining({ channel: 'telegram', senderId: '123', codeUsed: 'AABB11' }),
        expect.objectContaining({ channel: 'discord', senderId: '456', codeUsed: 'CC33DD' }),
      ]));
    });

    it('removeApproved deletes a sender', () => {
      const ps = store.getPairingStore();
      ps.saveApproved({ channel: 'telegram', senderId: '123', approvedAt: 1000, codeUsed: 'AABB11' });
      ps.removeApproved('telegram', '123');
      expect(ps.loadApproved()).toHaveLength(0);
    });

    it('saveApproved upserts on duplicate channel+senderId', () => {
      const ps = store.getPairingStore();
      ps.saveApproved({ channel: 'telegram', senderId: '123', approvedAt: 1000, codeUsed: 'FIRST1' });
      ps.saveApproved({ channel: 'telegram', senderId: '123', approvedAt: 2000, codeUsed: 'SECOND' });
      const loaded = ps.loadApproved();
      expect(loaded).toHaveLength(1);
      expect(loaded[0].codeUsed).toBe('SECOND');
    });
  });
});
