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

// Экран судится по тому, что видит человек, а не по внутреннему состоянию:
// переписанная реализация обязана остаться зелёной.

const assign = vi.fn()

vi.stubGlobal('window', { location: { assign } })

function answerWith(response: Partial<Response> & { json?: () => Promise<unknown> }) {
  vi.stubGlobal('fetch', vi.fn().mockResolvedValue(response))
}

function failWith(error: Error) {
  vi.stubGlobal('fetch', vi.fn().mockRejectedValue(error))
}

afterEach(() => {
  vi.restoreAllMocks()
  assign.mockReset()
})

describe('экран показывает вошедшего', () => {
  it('показывает имя, когда сессия есть', async () => {
    answerWith({
      ok: true,
      status: 200,
      json: () => Promise.resolve({ id: 'u1', name: 'Антон' }),
    })

    const screen = mount(HomeScreen)
    await flushPromises()

    expect(screen.text()).toContain('Антон')
    expect(assign).not.toHaveBeenCalled()
  })

  it('ведёт ко входу, когда сессии нет', async () => {
    answerWith({ ok: false, status: 401, json: () => Promise.resolve({}) })

    mount(HomeScreen)
    await flushPromises()

    expect(assign).toHaveBeenCalledWith('/auth/login')
  })

  it('на прочий отказ показывает строку и ко входу не ведёт', async () => {
    answerWith({
      ok: false,
      status: 500,
      json: () => Promise.resolve({ error_code: 'internal', message: 'Внутренняя ошибка сервиса' }),
    })

    const screen = mount(HomeScreen)
    await flushPromises()

    expect(screen.text()).toContain('Внутренняя ошибка сервиса')
    expect(assign).not.toHaveBeenCalled()
  })

  it('на сорванный запрос показывает, что связи нет', async () => {
    failWith(new Error('network down'))

    const screen = mount(HomeScreen)
    await flushPromises()

    expect(screen.text()).toContain('Связи нет')
    expect(assign).not.toHaveBeenCalled()
  })

  it('учётная запись без имени: вход выполнен, почты на экране нет', async () => {
    answerWith({
      ok: true,
      status: 200,
      json: () => Promise.resolve({ id: 'u1', name: '' }),
    })

    const screen = mount(HomeScreen)
    await flushPromises()

    expect(screen.text()).toContain('Вы вошли')
    expect(screen.text()).not.toContain('@')
  })
})
