import { assertEquals, assertExists } from 'jsr:@std/assert';
import { afterAll, beforeAll, describe, it } from 'jsr:@std/testing/bdd';
import { TypedRequest } from '@api.global/typedrequest';
import { createTestContainer, getTestPorts, loginAndGetIdentity } from './helpers/server.helper.ts';
import { ObjectStorageContainer } from '../ts/index.ts';
import type * as interfaces from '../ts_interfaces/index.ts';
import type { IReq_CreateBucket, IReq_DeleteBucket } from '../ts_interfaces/requests/buckets.ts';
import type { IReq_DeletePrefix, IReq_PutObject } from '../ts_interfaces/requests/objects.ts';
import type {
  IReq_GetClusterHealth,
  IReq_GetServerStatus,
} from '../ts_interfaces/requests/status.ts';
import type { IReq_GetServerConfig } from '../ts_interfaces/requests/config.ts';

const PORT_INDEX = 7;
const ports = getTestPorts(PORT_INDEX);
const url = `http://localhost:${ports.uiPort}/typedrequest`;
const BUCKET = 'stats-bucket';

describe('Status and config', { sanitizeResources: false, sanitizeOps: false }, () => {
  let container: ObjectStorageContainer;
  let identity: interfaces.data.IIdentity;

  beforeAll(async () => {
    container = createTestContainer(PORT_INDEX);
    await container.start();
    identity = await loginAndGetIdentity(ports.uiPort);

    // Create bucket with objects for stats testing
    const createBucket = new TypedRequest<IReq_CreateBucket>(url, 'createBucket');
    await createBucket.fire({ identity, bucketName: BUCKET });

    const putObj = new TypedRequest<IReq_PutObject>(url, 'putObject');
    await putObj.fire({
      identity,
      bucketName: BUCKET,
      key: 'file1.txt',
      base64Content: btoa('Content of file 1'),
      contentType: 'text/plain',
    });
    await putObj.fire({
      identity,
      bucketName: BUCKET,
      key: 'file2.txt',
      base64Content: btoa('Content of file 2'),
      contentType: 'text/plain',
    });
  });

  afterAll(async () => {
    try {
      const delPrefix = new TypedRequest<IReq_DeletePrefix>(url, 'deletePrefix');
      await delPrefix.fire({ identity, bucketName: BUCKET, prefix: '' });
      const delBucket = new TypedRequest<IReq_DeleteBucket>(url, 'deleteBucket');
      await delBucket.fire({ identity, bucketName: BUCKET });
    } catch { /* cleanup best-effort */ }
    await container.stop();
  });

  it('should get server status', async () => {
    const req = new TypedRequest<IReq_GetServerStatus>(url, 'getServerStatus');
    const response = await req.fire({ identity });
    const status = response.status;

    assertEquals(status.running, true);
    assertEquals(status.objstPort, ports.objstPort);
    assertEquals(status.uiPort, ports.uiPort);
    assertEquals(status.bucketCount, 1);
    assertEquals(status.totalObjectCount, 2);
    assertEquals(status.totalStorageBytes > 0, true);
    assertEquals(status.uptime >= 0, true);
    assertEquals(status.startedAt > 0, true);
    assertEquals(status.region, 'us-east-1');
    assertEquals(status.authEnabled, true);
  });

  it('should get connection info from status', async () => {
    const req = new TypedRequest<IReq_GetServerStatus>(url, 'getServerStatus');
    const response = await req.fire({ identity });
    const info = response.connectionInfo;

    assertExists(info.endpoint);
    assertEquals(info.port, ports.objstPort);
    assertExists(info.accessKey);
    assertEquals(info.region, 'us-east-1');
  });

  it('should get server config', async () => {
    const req = new TypedRequest<IReq_GetServerConfig>(url, 'getServerConfig');
    const response = await req.fire({ identity });
    const config = response.config;

    assertEquals(config.objstPort, ports.objstPort);
    assertEquals(config.uiPort, ports.uiPort);
    assertEquals(config.region, 'us-east-1');
    assertEquals(config.authEnabled, true);
    assertEquals(config.corsEnabled, false);
  });

  it('should report standalone cluster health', async () => {
    const req = new TypedRequest<IReq_GetClusterHealth>(url, 'getClusterHealth');
    const response = await req.fire({ identity });

    assertEquals(response.clusterHealth.enabled, false);
  });

  it('should reflect correct stats after adding objects', async () => {
    // Add a third object
    const putObj = new TypedRequest<IReq_PutObject>(url, 'putObject');
    await putObj.fire({
      identity,
      bucketName: BUCKET,
      key: 'file3.txt',
      base64Content: btoa('Content of file 3'),
      contentType: 'text/plain',
    });

    const req = new TypedRequest<IReq_GetServerStatus>(url, 'getServerStatus');
    const response = await req.fire({ identity });
    assertEquals(response.status.totalObjectCount, 3);
  });
});
