jest.mock('axios', () => ({
  __esModule: true,
  default: {
    request: jest.fn(),
    post: jest.fn(),
    isAxiosError: jest.fn((err) => Boolean(err?.isAxiosError)),
  },
  isAxiosError: jest.fn((err) => Boolean(err?.isAxiosError)),
}))

jest.mock('execa', () => ({
  execa: jest.fn(),
}))

import axios from 'axios'
import { GitHubProvider } from '../providers/github'

const mockedAxios = axios as jest.Mocked<typeof axios>

describe('GitHubProvider', () => {
  beforeEach(() => {
    jest.resetAllMocks()
    mockedAxios.isAxiosError.mockImplementation((err) => Boolean(err?.isAxiosError))
    process.env.GITHUB_TOKEN = 'ghp_testtoken000000000000000000'
  })

  afterEach(() => {
    delete process.env.GITHUB_TOKEN
  })

  test('parseIssueNumber aceita GH, owner/repo# e URL', () => {
    expect(GitHubProvider.parseIssueNumber('GH-123')).toBe(123)
    expect(GitHubProvider.parseIssueNumber('acme/api#456')).toBe(456)
    expect(GitHubProvider.parseIssueNumber('https://github.com/acme/api/issues/789')).toBe(789)
  })

  test('normalizeCardId converte referências GitHub para GH-number', () => {
    const provider = new GitHubProvider({
      owner: 'acme',
      repo: 'api',
      base_branch: 'main',
      auth: { token_env: 'GITHUB_TOKEN' },
    })

    expect(provider.normalizeCardId('acme/api#456')).toBe('GH-456')
    expect(provider.normalizeCardId('https://github.com/acme/api/issues/789')).toBe('GH-789')
  })

  test('createCard cria issue e retorna card id GH-number', async () => {
    mockedAxios.request.mockResolvedValueOnce({
      data: {
        number: 42,
        html_url: 'https://github.com/acme/api/issues/42',
        node_id: 'I_kwDO42',
      },
    } as any)

    const provider = new GitHubProvider({
      owner: 'acme',
      repo: 'api',
      base_branch: 'main',
      auth: { token_env: 'GITHUB_TOKEN' },
    })

    await expect(provider.createCard('Título', 'Descrição')).resolves.toBe('GH-42')
    expect(mockedAxios.request).toHaveBeenCalledWith(expect.objectContaining({
      method: 'POST',
      baseURL: 'https://api.github.com',
      url: '/repos/acme/api/issues',
      data: { title: 'Título', body: 'Descrição', labels: [] },
    }))
  })

  test('getLastComment segue rel=last e usa o último item real', async () => {
    mockedAxios.request
      .mockResolvedValueOnce({
        data: [{ body: '/bloqueado' }],
        headers: {
          link: '<https://api.github.com/repos/acme/api/issues/42/comments?per_page=100&page=2>; rel="last"',
        },
      } as any)
      .mockResolvedValueOnce({
        data: [{ body: '/bloqueado' }, { body: '/aprovado' }],
        headers: {},
      } as any)

    const provider = new GitHubProvider({
      owner: 'acme',
      repo: 'api',
      base_branch: 'main',
      auth: { token_env: 'GITHUB_TOKEN' },
    })

    await expect(provider.getLastComment('GH-42')).resolves.toBe('/aprovado')
    expect(mockedAxios.request).toHaveBeenNthCalledWith(1, expect.objectContaining({
      method: 'GET',
      url: '/repos/acme/api/issues/42/comments?per_page=100',
    }))
    expect(mockedAxios.request).toHaveBeenNthCalledWith(2, expect.objectContaining({
      method: 'GET',
      url: '/repos/acme/api/issues/42/comments?per_page=100&page=2',
    }))
  })

  test('requisições GitHub usam timeout explícito', async () => {
    mockedAxios.request.mockResolvedValueOnce({
      data: {
        number: 42,
        html_url: 'https://github.com/acme/api/issues/42',
        node_id: 'I_kwDO42',
      },
    } as any)

    const provider = new GitHubProvider({
      owner: 'acme',
      repo: 'api',
      base_branch: 'main',
      request_timeout_ms: 1234,
      auth: { token_env: 'GITHUB_TOKEN' },
    })

    await provider.createCard('Título', 'Descrição')

    expect(mockedAxios.request).toHaveBeenCalledWith(expect.objectContaining({
      timeout: 1234,
    }))
  })

  test('getLastComment reexecuta rate limit 429 respeitando retry sem delay', async () => {
    mockedAxios.request
      .mockRejectedValueOnce({
        isAxiosError: true,
        response: {
          status: 429,
          data: { message: 'rate limit' },
          headers: { 'retry-after': '0' },
        },
      })
      .mockResolvedValueOnce({
        data: [{ body: '/aprovado' }],
        headers: {},
      } as any)

    const provider = new GitHubProvider({
      owner: 'acme',
      repo: 'api',
      base_branch: 'main',
      retry_base_delay_ms: 0,
      auth: { token_env: 'GITHUB_TOKEN' },
    })

    await expect(provider.getLastComment('GH-42')).resolves.toBe('/aprovado')
    expect(mockedAxios.request).toHaveBeenCalledTimes(2)
  })
})
