import * as path from 'node:path';
import { FileSessionTreeProvider } from '../src/modules/netaclaw/session-tree/file_provider.js';
import { MySqlSessionTreeProvider } from '../src/modules/netaclaw/session-tree/mysql_provider.js';
import {
  createSessionTreeProvider,
  resolveAgentSessionTreeConfig,
} from '../src/modules/netaclaw/session-tree/factory.js';

describe('session-tree factory', () => {
  it('creates a file provider from agent session config and netaclaw data dir defaults', () => {
    const provider = createSessionTreeProvider({
      session: resolveAgentSessionTreeConfig(
        {
          backend: 'file',
        },
        {
          backend: 'mysql',
          dataDir: 'C:/neta-data',
        },
      ),
      cwd: 'C:/workspace/neta',
    });

    expect(provider).toBeInstanceOf(FileSessionTreeProvider);
    expect((provider as FileSessionTreeProvider).getSessionFilePath('session-1')).toBe(
      path.join('C:/neta-data', 'sessions', `${Buffer.from('session-1', 'utf8').toString('base64url')}.jsonl`),
    );
  });

  it('allows agent config to override the file session root dir', () => {
    const provider = createSessionTreeProvider({
      session: resolveAgentSessionTreeConfig(
        {
          backend: 'file',
          file: {
            rootDir: 'D:/custom-sessions',
          },
        },
        {
          backend: 'mysql',
          dataDir: 'C:/neta-data',
        },
      ),
      cwd: 'C:/workspace/neta',
    });

    expect(provider).toBeInstanceOf(FileSessionTreeProvider);
    expect((provider as FileSessionTreeProvider).getSessionFilePath('session-2')).toBe(
      path.join('D:/custom-sessions', `${Buffer.from('session-2', 'utf8').toString('base64url')}.jsonl`),
    );
  });

  it('creates a mysql provider when agent session backend is mysql', () => {
    const sessionRepo = {
      find: jest.fn(),
      findOne: jest.fn(),
      findOneBy: jest.fn(),
      save: jest.fn(),
      delete: jest.fn(),
    };
    const entryRepo = {
      find: jest.fn(),
      findOne: jest.fn(),
      findOneBy: jest.fn(),
      save: jest.fn(),
      delete: jest.fn(),
    };

    const provider = createSessionTreeProvider({
      session: resolveAgentSessionTreeConfig(
        {
          backend: 'mysql',
        },
        {
          backend: 'file',
          dataDir: 'C:/neta-data',
        },
      ),
      sessionRepo,
      entryRepo,
    });

    expect(provider).toBeInstanceOf(MySqlSessionTreeProvider);
  });

  it('throws when mysql backend is selected without repositories', () => {
    expect(() => createSessionTreeProvider({
      session: resolveAgentSessionTreeConfig(
        {
          backend: 'mysql',
        },
        {
          backend: 'file',
          dataDir: 'C:/neta-data',
        },
      ),
    })).toThrow('MySqlSessionTreeProvider requires both sessionRepo and entryRepo');
  });
});

describe('resolveAgentSessionTreeConfig', () => {
  it('defaults to the application backend when agent config is empty', () => {
    expect(resolveAgentSessionTreeConfig(undefined, {
      backend: 'file',
      dataDir: 'C:/neta-data',
    })).toEqual({
      backend: 'file',
      file: {
        rootDir: path.join('C:/neta-data', 'sessions'),
      },
    });
  });

  it('defaults to file backend when neither agent nor global config specifies a backend', () => {
    expect(resolveAgentSessionTreeConfig(undefined, {
      dataDir: 'C:/neta-data',
    })).toEqual({
      backend: 'file',
      file: {
        rootDir: path.join('C:/neta-data', 'sessions'),
      },
    });
  });

  it('keeps mysql agent config without injecting file-only options', () => {
    expect(resolveAgentSessionTreeConfig(
      {
        backend: 'mysql',
      },
      {
        backend: 'file',
        dataDir: 'C:/neta-data',
      },
    )).toEqual({
      backend: 'mysql',
    });
  });
});
