import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
import { mount } from '@vue/test-utils'
import Login from '../Login.vue'

const { pushMock, loginUserMock, checkAuthMock } = vi.hoisted(() => ({
  pushMock: vi.fn(),
  loginUserMock: vi.fn(),
  checkAuthMock: vi.fn(),
}))

vi.mock('vue-router', () => ({
  useRouter: vi.fn(() => ({ push: pushMock })),
}))

vi.mock('@/stores/auth', () => ({
  loginUser: loginUserMock,
  checkAuth: checkAuthMock,
}))

vi.mock('@/common/api', async () => {
  const actual = await vi.importActual<typeof import('@/common/api')>('@/common/api')
  return {
    ...actual,
    parseErrorResponse: vi.fn(async () => ({
      msg: 'bad credentials',
      code: 'INVALID_CREDENTIALS',
    })),
  }
})

describe('Login.vue', () => {
  beforeEach(() => {
    vi.clearAllMocks()
    checkAuthMock.mockResolvedValue(undefined)
    vi.stubGlobal('fetch', vi.fn())
  })

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

  it('hydrates auth state after successful login', async () => {
    const fetchMock = vi.mocked(fetch)
    fetchMock.mockResolvedValue({ ok: true } as Response)

    const wrapper = mount(Login)

    await wrapper.get('#email').setValue('test@example.com')
    await wrapper.get('#password').setValue('secret123')
    await wrapper.get('form').trigger('submit')

    await Promise.resolve()

    expect(loginUserMock).toHaveBeenCalledTimes(1)
    expect(checkAuthMock).toHaveBeenCalledTimes(1)
    expect(pushMock).toHaveBeenCalledWith({ path: '/' })

    const checkAuthOrder = checkAuthMock.mock.invocationCallOrder[0]
    const pushOrder = pushMock.mock.invocationCallOrder[0]
    expect(checkAuthOrder).toBeDefined()
    expect(pushOrder).toBeDefined()
    expect((checkAuthOrder ?? 0) < (pushOrder ?? 0)).toBe(true)
  })

  it('does not hydrate auth state when login fails', async () => {
    const fetchMock = vi.mocked(fetch)
    fetchMock.mockResolvedValue({ ok: false, status: 401 } as Response)

    const wrapper = mount(Login)

    await wrapper.get('#email').setValue('test@example.com')
    await wrapper.get('#password').setValue('badpassword')
    await wrapper.get('form').trigger('submit')

    await Promise.resolve()

    expect(loginUserMock).not.toHaveBeenCalled()
    expect(checkAuthMock).not.toHaveBeenCalled()
    expect(pushMock).not.toHaveBeenCalled()
  })
})
