import { describe, it, expect, beforeEach } from 'vitest'
import { mount, flushPromises } from '@vue/test-utils'
import { createRouter, createWebHistory } from 'vue-router'
import { setActivePinia, createPinia } from 'pinia'

import LoginPage from './LoginPage.vue'
import { useAuthStore } from '@/stores/auth'

// Mock window.location
const mockLocation = {
  href: '',
}
Object.defineProperty(window, 'location', {
  value: mockLocation,
  writable: true,
})

describe('LoginPage', () => {
  let router: ReturnType<typeof createRouter>

  beforeEach(() => {
    setActivePinia(createPinia())
    mockLocation.href = ''

    router = createRouter({
      history: createWebHistory(),
      routes: [
        { path: '/login', name: 'Login', component: LoginPage },
        { path: '/', name: 'Home', component: { template: '<div>Home</div>' } },
      ],
    })
  })

  describe('rendering', () => {
    it('shows OAuth buttons', () => {
      /**
       * Test that OAuth provider buttons are displayed.
       *
       * Users should see clear options to login with Google
       * or Discord - no username/password fields.
       */
      const wrapper = mount(LoginPage, {
        global: {
          plugins: [router],
        },
      })

      expect(wrapper.text()).toContain('Continue with Google')
      expect(wrapper.text()).toContain('Continue with Discord')
    })

    it('does not show username/password fields', () => {
      /**
       * Test that traditional auth fields are absent.
       *
       * This is an OAuth-only app - no username/password
       * inputs should exist.
       */
      const wrapper = mount(LoginPage, {
        global: {
          plugins: [router],
        },
      })

      expect(wrapper.find('input[type="text"]').exists()).toBe(false)
      expect(wrapper.find('input[type="password"]').exists()).toBe(false)
    })
  })

  describe('OAuth flow', () => {
    it('redirects to Google OAuth on button click', async () => {
      /**
       * Test that clicking Google button starts OAuth flow.
       *
       * The button should redirect the browser to the backend's
       * Google OAuth endpoint.
       */
      const wrapper = mount(LoginPage, {
        global: {
          plugins: [router],
        },
      })

      const auth = useAuthStore()
      const expectedUrl = auth.getOAuthUrl('google')

      const googleButton = wrapper.findAll('button').find(b => b.text().includes('Google'))
      expect(googleButton).toBeTruthy()

      await googleButton!.trigger('click')

      expect(mockLocation.href).toBe(expectedUrl)
    })

    it('redirects to Discord OAuth on button click', async () => {
      /**
       * Test that clicking Discord button starts OAuth flow.
       *
       * The button should redirect the browser to the backend's
       * Discord OAuth endpoint.
       */
      const wrapper = mount(LoginPage, {
        global: {
          plugins: [router],
        },
      })

      const auth = useAuthStore()
      const expectedUrl = auth.getOAuthUrl('discord')

      const discordButton = wrapper.findAll('button').find(b => b.text().includes('Discord'))
      expect(discordButton).toBeTruthy()

      await discordButton!.trigger('click')

      expect(mockLocation.href).toBe(expectedUrl)
    })

    it('shows loading state after button click', async () => {
      /**
       * Test that loading indicator appears during redirect.
       *
       * While the browser is redirecting, users should see
       * feedback that something is happening.
       */
      const wrapper = mount(LoginPage, {
        global: {
          plugins: [router],
        },
      })

      const googleButton = wrapper.findAll('button').find(b => b.text().includes('Google'))
      await googleButton!.trigger('click')

      expect(wrapper.text()).toContain('Redirecting to login')
    })

    it('disables buttons while loading', async () => {
      /**
       * Test that buttons are disabled during redirect.
       *
       * Prevents users from clicking multiple times while
       * the OAuth redirect is in progress.
       */
      const wrapper = mount(LoginPage, {
        global: {
          plugins: [router],
        },
      })

      const googleButton = wrapper.findAll('button').find(b => b.text().includes('Google'))
      await googleButton!.trigger('click')

      const buttons = wrapper.findAll('button')
      buttons.forEach(button => {
        expect(button.attributes('disabled')).toBeDefined()
      })
    })
  })

  describe('error handling', () => {
    it('shows error from query params', async () => {
      /**
       * Test that OAuth errors are displayed.
       *
       * When OAuth fails, the callback redirects back to login
       * with error details in query params.
       */
      await router.push('/login?error=oauth_failed&message=Invalid%20credentials')
      await router.isReady()

      const wrapper = mount(LoginPage, {
        global: {
          plugins: [router],
        },
      })

      await flushPromises()

      expect(wrapper.text()).toContain('Invalid credentials')
    })

    it('shows default error message when message is missing', async () => {
      /**
       * Test that a default error message is shown.
       *
       * If the error query param is present but message is
       * missing, show a generic error.
       */
      await router.push('/login?error=oauth_failed')
      await router.isReady()

      const wrapper = mount(LoginPage, {
        global: {
          plugins: [router],
        },
      })

      await flushPromises()

      expect(wrapper.text()).toContain('Authentication failed')
    })
  })
})
