import { assertEquals, assertExists } from '@std/assert';
import { StorageManager } from '../ts/storage/index.ts';
import * as smartsecret from '@push.rocks/smartsecret';

Deno.test('StorageManager memory: set and get', async () => {
  const sm = new StorageManager({ backend: 'memory' });
  await sm.set('/test/key1', 'hello');
  const result = await sm.get('/test/key1');
  assertEquals(result, 'hello');
});

Deno.test('StorageManager memory: get nonexistent returns null', async () => {
  const sm = new StorageManager({ backend: 'memory' });
  const result = await sm.get('/missing');
  assertEquals(result, null);
});

Deno.test('StorageManager memory: delete', async () => {
  const sm = new StorageManager({ backend: 'memory' });
  await sm.set('/test/key1', 'hello');
  const deleted = await sm.delete('/test/key1');
  assertEquals(deleted, true);
  const result = await sm.get('/test/key1');
  assertEquals(result, null);
});

Deno.test('StorageManager memory: delete nonexistent returns false', async () => {
  const sm = new StorageManager({ backend: 'memory' });
  const deleted = await sm.delete('/missing');
  assertEquals(deleted, false);
});

Deno.test('StorageManager memory: exists', async () => {
  const sm = new StorageManager({ backend: 'memory' });
  assertEquals(await sm.exists('/test/key1'), false);
  await sm.set('/test/key1', 'hello');
  assertEquals(await sm.exists('/test/key1'), true);
});

Deno.test('StorageManager memory: list keys under prefix', async () => {
  const sm = new StorageManager({ backend: 'memory' });
  await sm.set('/connections/a.json', '{}');
  await sm.set('/connections/b.json', '{}');
  await sm.set('/other/c.json', '{}');
  const keys = await sm.list('/connections/');
  assertEquals(keys, ['/connections/a.json', '/connections/b.json']);
});

Deno.test('StorageManager memory: getJSON and setJSON roundtrip', async () => {
  const sm = new StorageManager({ backend: 'memory' });
  const data = { id: '123', name: 'test', nested: { value: 42 } };
  await sm.setJSON('/data/item.json', data);
  const result = await sm.getJSON<typeof data>('/data/item.json');
  assertEquals(result, data);
});

Deno.test('StorageManager memory: getJSON nonexistent returns null', async () => {
  const sm = new StorageManager({ backend: 'memory' });
  const result = await sm.getJSON('/missing.json');
  assertEquals(result, null);
});

Deno.test('StorageManager: key validation requires leading slash', async () => {
  const sm = new StorageManager({ backend: 'memory' });
  let threw = false;
  try {
    await sm.get('no-slash');
  } catch {
    threw = true;
  }
  assertEquals(threw, true);
});

Deno.test('StorageManager: key normalization strips ..', async () => {
  const sm = new StorageManager({ backend: 'memory' });
  await sm.set('/test/../actual/key', 'value');
  // '..' segments are stripped, so key becomes /test/actual/key — wait,
  // the normalizer filters out '..' segments entirely
  // /test/../actual/key -> segments: ['test', 'actual', 'key'] (.. filtered)
  const result = await sm.get('/test/actual/key');
  assertEquals(result, 'value');
});

Deno.test('StorageManager filesystem: set, get, delete roundtrip', async () => {
  const tmpDir = await Deno.makeTempDir();
  const sm = new StorageManager({ backend: 'filesystem', fsPath: tmpDir });
  try {
    await sm.set('/test/file.txt', 'filesystem content');
    const result = await sm.get('/test/file.txt');
    assertEquals(result, 'filesystem content');

    assertEquals(await sm.exists('/test/file.txt'), true);

    const deleted = await sm.delete('/test/file.txt');
    assertEquals(deleted, true);
    assertEquals(await sm.get('/test/file.txt'), null);
  } finally {
    await Deno.remove(tmpDir, { recursive: true });
  }
});

Deno.test('StorageManager filesystem: list keys', async () => {
  const tmpDir = await Deno.makeTempDir();
  const sm = new StorageManager({ backend: 'filesystem', fsPath: tmpDir });
  try {
    await sm.setJSON('/items/a.json', { id: 'a' });
    await sm.setJSON('/items/b.json', { id: 'b' });
    const keys = await sm.list('/items/');
    assertEquals(keys, ['/items/a.json', '/items/b.json']);
  } finally {
    await Deno.remove(tmpDir, { recursive: true });
  }
});

Deno.test('ConnectionManager with StorageManager: create and load', async () => {
  const { ConnectionManager } = await import('../ts/classes/connectionmanager.ts');
  const sm = new StorageManager({ backend: 'memory' });
  const secret = new smartsecret.SmartSecret({ service: 'gitops-test' });
  const cm = new ConnectionManager(sm, secret);
  await cm.init();

  // Create a connection
  const conn = await cm.createConnection('test', 'gitea', 'https://gitea.example.com', 'token');
  assertExists(conn.id);
  assertEquals(conn.name, 'test');
  assertEquals(conn.token, '***');

  // Verify it's stored in StorageManager
  const stored = await sm.getJSON<{ id: string }>(`/connections/${conn.id}.json`);
  assertExists(stored);
  assertEquals(stored.id, conn.id);

  // Create a new ConnectionManager and verify it loads the connection
  const cm2 = new ConnectionManager(sm, secret);
  await cm2.init();
  const conns = cm2.getConnections();
  assertEquals(conns.length, 1);
  assertEquals(conns[0].id, conn.id);

  // Wait for background health checks to avoid resource leaks
  await cm.healthCheckDone;
  await cm2.healthCheckDone;
});
