import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
import type { TaskObject } from '@zync/types'
import { jiraAdapter } from '../src/tasks/jira'

describe('jiraAdapter SSRF guard', () => {
  const fetchMock = vi.fn()

  beforeEach(() => {
    vi.stubGlobal('fetch', fetchMock)
  })

  afterEach(() => {
    vi.unstubAllGlobals()
    fetchMock.mockReset()
  })

  it('rejects private baseUrl before fetchTasks calls fetch', async () => {
    await expect(
      jiraAdapter.fetchTasks({
        baseUrl: 'http://127.0.0.1:8080',
        email: 'user@example.com',
        apiToken: 'token',
      }),
    ).rejects.toThrow('URL must be a public HTTPS endpoint')

    expect(fetchMock).not.toHaveBeenCalled()
  })

  it('allows public HTTPS atlassian baseUrl', async () => {
    fetchMock.mockResolvedValue({
      ok: true,
      json: async () => ({ issues: [] }),
    })

    await expect(
      jiraAdapter.fetchTasks({
        baseUrl: 'https://my-company.atlassian.net',
        email: 'user@example.com',
        apiToken: 'token',
      }),
    ).resolves.toEqual([])

    expect(fetchMock).toHaveBeenCalledOnce()
    expect(fetchMock.mock.calls[0]?.[1]).toMatchObject({ redirect: 'manual' })
  })

  it('rejects redirect responses from fetchTasks (no follow to internal IP)', async () => {
    fetchMock.mockResolvedValue({
      ok: false,
      status: 302,
      json: async () => ({}),
    })

    await expect(
      jiraAdapter.fetchTasks({
        baseUrl: 'https://my-company.atlassian.net',
        email: 'user@example.com',
        apiToken: 'token',
      }),
    ).rejects.toThrow('Jira API error: 302')

    expect(fetchMock.mock.calls[0]?.[1]).toMatchObject({ redirect: 'manual' })
  })

  it('uses redirect manual on pushUpdate fetch', async () => {
    fetchMock.mockResolvedValue({ ok: true, status: 204 })

    const pushUpdate = jiraAdapter.pushUpdate
    expect(pushUpdate).toBeDefined()

    await pushUpdate!(
      {
        external_id: 'PROJ-1',
        title: 'Updated',
        due_date: null,
      } as TaskObject,
      {
        baseUrl: 'https://my-company.atlassian.net',
        email: 'user@example.com',
        apiToken: 'token',
      },
    )

    expect(fetchMock.mock.calls[0]?.[1]).toMatchObject({ redirect: 'manual', method: 'PUT' })
  })
})
