// @vitest-environment happy-dom
//
// credentialAccount imports hostFromIp from serverPins, which hydrates from
// localStorage at module init — same reason serverPins.test.js scopes a DOM
// to itself rather than switching the global vitest environment.
//
// Every expectation below is a LITERAL string, and each one is also asserted
// verbatim in the Rust twin (`credential_account_key`'s tests in
// crates/cambium-core/src/auth.rs). The CLI and this app share one credential
// store, so if either language's fold drifts, one of the two suites breaks.
import { describe, expect, it } from 'vitest';
import { credentialAccountKey } from './credentialAccount';

describe('credentialAccountKey', () => {
  it('folds handle case', () => {
    expect(credentialAccountKey('host.example:8666', '@GINA')).toBe(
      'host.example:8666|@gina'
    );
    expect(credentialAccountKey('host.example:8666', '@GiNa')).toBe(
      'host.example:8666|@gina'
    );
    expect(credentialAccountKey('host.example:8666', '@GINA')).toBe(
      credentialAccountKey('host.example:8666', '@gina')
    );
  });

  it('forces exactly one leading @', () => {
    expect(credentialAccountKey('host.example:8666', 'gina')).toBe(
      'host.example:8666|@gina'
    );
    expect(credentialAccountKey('host.example:8666', '@@GINA')).toBe(
      'host.example:8666|@gina'
    );
    // An empty handle stays empty rather than becoming a bare "@".
    expect(credentialAccountKey('host.example:8666', '@')).toBe('host.example:8666|');
  });

  it('folds host case', () => {
    expect(credentialAccountKey('Host.Example:8666', '@gina')).toBe(
      'host.example:8666|@gina'
    );
    expect(credentialAccountKey('LOCALHOST:8666', '@gina')).toBe('localhost:8666|@gina');
  });

  it('folds only ASCII letters', () => {
    // Deliberate: plain toLowerCase() would fold "É" too, and JS, Rust and
    // Python disagree on non-ASCII mappings — an ASCII-only fold is the only
    // one that is byte-identical across the faces sharing this store.
    expect(credentialAccountKey('h:1', '@ÉLODIE')).toBe('h:1|@Élodie');
  });

  it('derives the bare host from a connection-card ip', () => {
    // Rust's callers hand in an already-bare host (executor::bare_host /
    // auth::parse_host); the GUI's ip field may carry a scheme, a path and
    // stray whitespace, so the helper runs hostFromIp itself.
    expect(credentialAccountKey('  https://VPS.example:8666/api ', '@Gina')).toBe(
      'vps.example:8666|@gina'
    );
    expect(credentialAccountKey('http://10.0.0.5:8666', 'GINA')).toBe(
      '10.0.0.5:8666|@gina'
    );
  });

  it('tolerates missing inputs', () => {
    expect(credentialAccountKey(null, null)).toBe('|');
    expect(credentialAccountKey(undefined, '@Gina')).toBe('|@gina');
  });
});
