// Handle / tag-name parsing for the protocol adapter. Pure functions, no
// mocks needed — the contract here is the entry point both adapter
// implementations rely on.

import { normaliseTagName, parseHandle } from '../../src/lib/protocol/handle'

describe('parseHandle', () => {
  const ACTIVE = 'pixelfed.social'

  it('treats a bare local handle as local', () => {
    expect(parseHandle('COSCUP', ACTIVE)).toEqual({
      raw: 'COSCUP',
      localPart: 'COSCUP',
      host: null,
      isLocalToActiveAccount: true,
      acct: 'COSCUP',
    })
  })

  it('strips a leading @', () => {
    expect(parseHandle('@COSCUP', ACTIVE)).toMatchObject({
      localPart: 'COSCUP',
      host: null,
      isLocalToActiveAccount: true,
    })
  })

  it('strips multiple leading @', () => {
    expect(parseHandle('@@@COSCUP', ACTIVE)).toMatchObject({
      localPart: 'COSCUP',
      host: null,
    })
  })

  it('splits user@host into local + host parts', () => {
    expect(parseHandle('@COSCUP@hollo.social', ACTIVE)).toEqual({
      raw: '@COSCUP@hollo.social',
      localPart: 'COSCUP',
      host: 'hollo.social',
      isLocalToActiveAccount: false,
      acct: 'COSCUP@hollo.social',
    })
  })

  it('marks user@activeInstance as local (case-insensitive)', () => {
    expect(parseHandle('@alice@PIXELFED.SOCIAL', ACTIVE).isLocalToActiveAccount).toBe(true)
    expect(parseHandle('alice@pixelfed.social', ACTIVE).isLocalToActiveAccount).toBe(true)
  })

  it('trims whitespace before parsing', () => {
    expect(parseHandle('  @alice@host  ', ACTIVE)).toMatchObject({
      localPart: 'alice',
      host: 'host',
    })
  })

  it('lowercases the host for stable equality', () => {
    expect(parseHandle('alice@HoLLo.Social', ACTIVE).host).toBe('hollo.social')
  })

  it('handles empty input without throwing', () => {
    const h = parseHandle('', ACTIVE)
    expect(h.localPart).toBe('')
    expect(h.host).toBeNull()
  })
})

describe('normaliseTagName', () => {
  it('strips a leading #', () => {
    expect(normaliseTagName('#japanese')).toBe('japanese')
  })

  it('strips multiple leading # so #### tags do not 422 the server', () => {
    expect(normaliseTagName('###tag')).toBe('tag')
  })

  it('trims whitespace', () => {
    expect(normaliseTagName('  japanese  ')).toBe('japanese')
  })

  it('preserves Unicode word chars (hiragana, katakana, hanzi)', () => {
    // Mastodon's `/\A[[:word:]]+\z/` accepts these — the adapter must not
    // strip them.
    expect(normaliseTagName('#ひらがな')).toBe('ひらがな')
    expect(normaliseTagName('#漢字')).toBe('漢字')
  })

  it('handles empty / null-ish input', () => {
    expect(normaliseTagName('')).toBe('')
    expect(normaliseTagName('#')).toBe('')
  })
})
