// `pushReplyComposer` seam tests. The helper is the single seam every reply
// affordance routes through (post-detail anchor message-icon, per-row
// CommentItem text label, AncestorRow); a regression here breaks every
// reply path in the app simultaneously, so the contract is tiny but worth
// pinning.
//
// Two load-bearing invariants:
//   1. Null / missing-id targets are no-ops — never throw, never push a
//      malformed `/camera?inReplyToId=undefined` URL the camera screen
//      would have to defensively guard against.
//   2. The pushed URL matches the existing quote-push convention at
//      `FeedPost.tsx:804` (`router.push(\`/camera?quotedStatusId=${id}\`)`)
//      so a single `rg '/camera?'` finds every entry point.

const mockRouterPush = jest.fn()

jest.mock('expo-router', () => ({
  router: { push: (path: string) => mockRouterPush(path) },
}))

type ReplyComposerModule = typeof import('../src/lib/replyComposer')
type Status = import('../src/lib/api-types').Status

let pushReplyComposer: ReplyComposerModule['pushReplyComposer']

beforeAll(() => {
  pushReplyComposer = (
    require('../src/lib/replyComposer') as ReplyComposerModule
  ).pushReplyComposer
})

beforeEach(() => {
  mockRouterPush.mockReset()
})

function statusFixture(overrides: Partial<Status> = {}): Status {
  // Helper consumes `target?.id` only — pad the rest with the type
  // assertion rather than dragging in 80 fields of MastoAPI noise.
  return overrides as unknown as Status
}

describe('pushReplyComposer', () => {
  it('pushes /camera?inReplyToId=<id> for a target with an id', () => {
    pushReplyComposer(statusFixture({ id: 'abc-123' }))
    expect(mockRouterPush).toHaveBeenCalledTimes(1)
    expect(mockRouterPush).toHaveBeenCalledWith('/camera?inReplyToId=abc-123')
  })

  it('matches the existing quote-push template-string convention', () => {
    // Locks the URL shape so a single `rg '/camera?'` keeps finding every
    // entry point (the quote affordance pushes
    // `router.push(\`/camera?quotedStatusId=${post.id}\`)` per
    // `FeedPost.tsx:804`).
    pushReplyComposer(statusFixture({ id: '42' }))
    const url = mockRouterPush.mock.calls[0][0] as string
    expect(url.startsWith('/camera?')).toBe(true)
    expect(url.includes('inReplyToId=42')).toBe(true)
  })

  it('is a no-op when target is null', () => {
    pushReplyComposer(null)
    expect(mockRouterPush).not.toHaveBeenCalled()
  })

  it('is a no-op when target is undefined', () => {
    pushReplyComposer(undefined)
    expect(mockRouterPush).not.toHaveBeenCalled()
  })

  it('is a no-op when target.id is missing (defensive)', () => {
    // Synthetic placeholders constructed by `remote-outbox` ingestion or
    // a stale-cache read may surface a Status-shaped object with an empty
    // id; the helper must short-circuit rather than push a malformed URL.
    pushReplyComposer(statusFixture({ id: '' }))
    expect(mockRouterPush).not.toHaveBeenCalled()
  })
})
