import { describe, it, expect, vi, beforeEach } from 'vitest'
import { createRouter, createWebHistory } from 'vue-router'

// Use plain objects — the guard only reads `.value`, so full Vue refs are unnecessary
const { isAuthReadyMock, isUserLoggedInMock, isParentAuthenticatedMock } = vi.hoisted(() => ({
  isAuthReadyMock: { value: true },
  isUserLoggedInMock: { value: false },
  isParentAuthenticatedMock: { value: false },
}))

vi.mock('@/stores/auth', () => ({
  isAuthReady: isAuthReadyMock,
  isUserLoggedIn: isUserLoggedInMock,
  isParentAuthenticated: isParentAuthenticatedMock,
  enforceParentExpiry: vi.fn(),
  setPendingReturnUrl: vi.fn(),
}))

// Import router AFTER mocks are in place
const { default: router } = await import('../index')

// Helper — navigate and return the resolved path
async function navigate(path: string): Promise<string> {
  await router.push(path)
  return router.currentRoute.value.path
}

describe('router auth guard', () => {
  beforeEach(async () => {
    isAuthReadyMock.value = true
    // Park at /auth/reset-password as a neutral starting point:
    // - it is always reachable when logged out
    // - it doesn't match any route a test assertion lands on
    isUserLoggedInMock.value = false
    isParentAuthenticatedMock.value = false
    await router.push('/auth/reset-password')
  })

  // ── Redirect logged-in users away from /auth ──────────────────────────────

  it('redirects logged-in parent user from /auth to /parent', async () => {
    isUserLoggedInMock.value = true
    isParentAuthenticatedMock.value = true

    const path = await navigate('/auth')
    expect(path).toBe('/parent')
  })

  it('redirects logged-in child user from /auth to /child', async () => {
    isUserLoggedInMock.value = true
    isParentAuthenticatedMock.value = false

    const path = await navigate('/auth')
    expect(path).toBe('/child')
  })

  it('redirects logged-in parent user from /auth/login to /parent', async () => {
    isUserLoggedInMock.value = true
    isParentAuthenticatedMock.value = true

    const path = await navigate('/auth/login')
    expect(path).toBe('/parent')
  })

  it('redirects logged-in child user from /auth/signup to /child', async () => {
    isUserLoggedInMock.value = true
    isParentAuthenticatedMock.value = false

    const path = await navigate('/auth/signup')
    expect(path).toBe('/child')
  })

  it('redirects logged-in child user from /auth/forgot-password to /child', async () => {
    isUserLoggedInMock.value = true
    isParentAuthenticatedMock.value = false

    const path = await navigate('/auth/forgot-password')
    expect(path).toBe('/child')
  })

  it('allows logged-in parent user to access /auth/reset-password', async () => {
    isUserLoggedInMock.value = true
    isParentAuthenticatedMock.value = true

    const path = await navigate('/auth/reset-password')
    expect(path).toBe('/auth/reset-password')
  })

  it('allows logged-in child user to access /auth/reset-password', async () => {
    isUserLoggedInMock.value = true
    isParentAuthenticatedMock.value = false

    const path = await navigate('/auth/reset-password')
    expect(path).toBe('/auth/reset-password')
  })

  // ── Unauthenticated users may access /auth ────────────────────────────────

  it('allows unauthenticated user to access /auth', async () => {
    isUserLoggedInMock.value = false

    const path = await navigate('/auth')
    expect(path).toBe('/auth')
  })

  it('allows unauthenticated user to access /auth/login', async () => {
    isUserLoggedInMock.value = false

    const path = await navigate('/auth/login')
    expect(path).toBe('/auth/login')
  })

  // ── Unauthenticated users are redirected to / from protected routes ────────

  it('redirects unauthenticated user from /parent to /', async () => {
    isUserLoggedInMock.value = false

    const path = await navigate('/parent')
    expect(path).toBe('/')
  })

  it('redirects unauthenticated user from /child to /', async () => {
    isUserLoggedInMock.value = false

    const path = await navigate('/child')
    expect(path).toBe('/')
  })

  // ── Authenticated users are routed to the correct section ─────────────────

  it('allows parent-authenticated user to access /parent', async () => {
    isUserLoggedInMock.value = true
    isParentAuthenticatedMock.value = true

    const path = await navigate('/parent')
    expect(path).toBe('/parent')
  })

  it('allows child user to access /child', async () => {
    isUserLoggedInMock.value = true
    isParentAuthenticatedMock.value = false

    const path = await navigate('/child')
    expect(path).toBe('/child')
  })

  it('redirects child user away from /parent to /child', async () => {
    isUserLoggedInMock.value = true
    isParentAuthenticatedMock.value = false

    const path = await navigate('/parent')
    expect(path).toBe('/child')
  })

  it('redirects parent user away from /child to /parent', async () => {
    isUserLoggedInMock.value = true
    isParentAuthenticatedMock.value = true

    const path = await navigate('/child')
    expect(path).toBe('/parent')
  })

  // ── ParentPinSetup is always accessible ───────────────────────────────────

  it('allows access to /parent/pin-setup regardless of auth state', async () => {
    isUserLoggedInMock.value = false

    const path = await navigate('/parent/pin-setup')
    expect(path).toBe('/parent/pin-setup')
  })

  // ── Landing page (/) ────────────────────────────────────────────────────────

  it('allows unauthenticated user to access / (landing page)', async () => {
    isUserLoggedInMock.value = false

    const path = await navigate('/')
    expect(path).toBe('/')
  })

  it('redirects logged-in child user from / to /child', async () => {
    isUserLoggedInMock.value = true
    isParentAuthenticatedMock.value = false

    const path = await navigate('/')
    expect(path).toBe('/child')
  })

  it('redirects logged-in parent user from / to /parent', async () => {
    isUserLoggedInMock.value = true
    isParentAuthenticatedMock.value = true

    const path = await navigate('/')
    expect(path).toBe('/parent')
  })
})
