import { beforeEach, describe, expect, it, vi } from 'vitest'
import { readConfig } from '../src/config'
import { mountPasswordLogin } from '../src/login-password'

const cfg = readConfig({
  protocol: 'https:',
  host: 'alice.term.example.com',
  hostname: 'alice.term.example.com',
})

function okFetch(): typeof fetch {
  return vi.fn(async () => ({ ok: true, status: 200, json: async () => ({}) }) as Response) as unknown as typeof fetch
}
function rejectFetch(): typeof fetch {
  return vi.fn(async () => ({ ok: false, status: 401, json: async () => ({}) }) as Response) as unknown as typeof fetch
}

describe('mountPasswordLogin — v0.8 gate (T3)', () => {
  let root: HTMLElement
  beforeEach(() => {
    root = document.createElement('div')
    document.body.append(root)
  })

  it('correct token → "ok" and issues a credentialed cookie login request', async () => {
    const fetchImpl = okFetch()
    const onSuccess = vi.fn()
    const login = mountPasswordLogin(root, cfg, { fetchImpl, onSuccess })
    await expect(login.submit('s3cret')).resolves.toBe('ok')
    expect(onSuccess).toHaveBeenCalledOnce()
    const call = (fetchImpl as unknown as ReturnType<typeof vi.fn>).mock.calls[0]!
    const init = call[1] as RequestInit
    expect(init.credentials).toBe('include')
    expect(JSON.parse(init.body as string)).toEqual({ clientToken: 's3cret' })
  })

  it('wrong token → "rejected", no onSuccess, error shown via textContent (no innerHTML)', async () => {
    const login = mountPasswordLogin(root, cfg, { fetchImpl: rejectFetch() })
    await expect(login.submit('nope')).resolves.toBe('rejected')
    const err = root.querySelector('.login-error') as HTMLElement
    expect(err.textContent).toBe('Invalid access token.')
    expect(err.innerHTML).toBe('Invalid access token.') // textContent-set, no markup injected
  })

  it('empty input keeps submit disabled (fail-fast) and submit("") is rejected without a fetch', async () => {
    const fetchImpl = okFetch()
    const login = mountPasswordLogin(root, cfg, { fetchImpl })
    const button = root.querySelector('button') as HTMLButtonElement
    expect(button.disabled).toBe(true)
    await expect(login.submit('')).resolves.toBe('rejected')
    expect(fetchImpl).not.toHaveBeenCalled()
  })

  it('does not persist the token to localStorage', async () => {
    const login = mountPasswordLogin(root, cfg, { fetchImpl: okFetch() })
    await login.submit('s3cret')
    expect(JSON.stringify(localStorage)).not.toContain('s3cret')
  })
})
