import { describe, expect, it } from 'vitest'
import type { RouteLocationNormalized } from 'vue-router'

import { createAuthGuard, router } from '@/router'
import type { useAuthStore } from '@/stores/authStore'

type AuthStoreForGuard = ReturnType<typeof useAuthStore>

function createRoute(
  path: string,
  meta: Record<string, unknown> = {},
  overrides: Partial<RouteLocationNormalized> = {},
): RouteLocationNormalized {
  return {
    fullPath: path,
    path,
    name: undefined,
    params: {},
    query: {},
    hash: '',
    matched: [],
    meta,
    redirectedFrom: undefined,
    ...overrides,
  } as RouteLocationNormalized
}

function createAuthStoreForGuard(overrides: Partial<AuthStoreForGuard> = {}): AuthStoreForGuard {
  return {
    restoreAttempted: true,
    isAuthenticated: true,
    firstMenuPath: '/reservation/orders',
    hasStoredToken: () => false,
    restoreFromSession: async () => true,
    hasPermission: () => true,
    ...overrides,
  } as unknown as AuthStoreForGuard
}

describe('reservation router', () => {
  it('exposes the P0 frontend routes', () => {
    expect(router.resolve('/login').name).toBe('login')
    expect(router.resolve('/reservation/orders').name).toBe('reservation-order-list')
    expect(router.resolve('/reservation/tasks').name).toBe('reservation-task-list')
    expect(router.resolve('/reservation/orders/20001').name).toBe('reservation-order-detail')
    expect(router.resolve('/reservation/tasks/10001').name).toBe('reservation-task-detail')
    expect(router.resolve('/reservation/source-messages/30001/conversation').name).toBe(
      'reservation-source-message-conversation',
    )
  })

  it('exposes the Debug EML route', () => {
    expect(router.resolve('/debug/eml-superagent').name).toBe('debug-eml-superagent')
  })

  it('exposes the System Admin V1 routes', () => {
    expect(router.resolve('/system/users').name).toBe('system-users')
    expect(router.resolve('/system/roles').name).toBe('system-roles')
    expect(router.resolve('/system/menus').name).toBe('system-menus')
    expect(router.resolve('/system/hotels').name).toBe('system-hotels')
    expect(router.resolve('/system/audits').name).toBe('system-audits')
    expect(router.resolve('/system/not-ready').name).toBe('not-found')
  })

  it('declares permissions for protected P0 routes', () => {
    expect(router.resolve('/reservation/orders').meta.permission).toBe('RESERVATION_ORDER_READ')
    expect(router.resolve('/reservation/orders/20001').meta.permission).toBe('RESERVATION_ORDER_READ')
    expect(router.resolve('/reservation/tasks').meta.permission).toBe('RESERVATION_TASK_READ')
    expect(router.resolve('/reservation/tasks/10001').meta.permission).toBe('RESERVATION_TASK_READ')
    expect(router.resolve('/reservation/source-messages/30001/conversation').meta.permission).toBe(
      'SOURCE_MESSAGE_ORIGINAL_READ',
    )
    expect(router.resolve('/debug/eml-superagent').meta.permission).toBe('SYSTEM_DEBUG_EML_RUN')
    expect(router.resolve('/system/users').meta.permission).toBe('SYSTEM_USER_MANAGE')
    expect(router.resolve('/system/roles').meta.permission).toBe('SYSTEM_ROLE_MANAGE')
    expect(router.resolve('/system/menus').meta.permission).toBe('SYSTEM_MENU_MANAGE')
    expect(router.resolve('/system/hotels').meta.permission).toBe('HOTEL_MANAGE')
    expect(router.resolve('/system/audits').meta.permission).toBe('SYSTEM_ADMIN_CONSOLE_ACCESS')
  })

  it('redirects anonymous users to login with the protected target as redirect', async () => {
    const guard = createAuthGuard(() =>
      createAuthStoreForGuard({
        isAuthenticated: false,
      }),
    )

    await expect(guard(createRoute('/reservation/orders', { permission: 'RESERVATION_ORDER_READ' }))).resolves.toEqual({
      path: '/login',
      query: {
        redirect: '/reservation/orders',
      },
    })
  })

  it('redirects authenticated users without route permission to the unauthorized page', async () => {
    const guard = createAuthGuard(() =>
      createAuthStoreForGuard({
        hasPermission: () => false,
      }),
    )

    await expect(guard(createRoute('/debug/eml-superagent', { permission: 'SYSTEM_DEBUG_EML_RUN' }))).resolves.toEqual({
      name: 'unauthorized',
    })
  })

  it('redirects the root route to the restored first backend menu', async () => {
    let restored = false
    let authenticated = false
    let firstMenuPath: string | null = null
    const authStore = {
      restoreAttempted: false,
      get isAuthenticated() {
        return authenticated
      },
      get firstMenuPath() {
        return firstMenuPath
      },
      hasStoredToken: () => true,
      restoreFromSession: async () => {
        restored = true
        authStore.restoreAttempted = true
        authenticated = true
        firstMenuPath = '/reservation/tasks'
        return true
      },
      hasPermission: () => true,
    } as unknown as AuthStoreForGuard
    const guard = createAuthGuard(() => authStore)

    await expect(guard(createRoute('/'))).resolves.toBe('/reservation/tasks')
    expect(restored).toBe(true)
  })

  it('redirects the System Admin entry to the first allowed management page', async () => {
    const guard = createAuthGuard(() =>
      createAuthStoreForGuard({
        hasPermission: (permission: string) =>
          permission === 'SYSTEM_ADMIN_CONSOLE_ACCESS' || permission === 'HOTEL_MANAGE',
      }),
    )

    await expect(guard(createRoute('/system', { permission: 'SYSTEM_ADMIN_CONSOLE_ACCESS' }))).resolves.toBe(
      '/system/hotels',
    )
  })

  it('redirects the root route to the default page when the backend menu points to root', async () => {
    const guard = createAuthGuard(() =>
      createAuthStoreForGuard({
        firstMenuPath: '/',
      }),
    )

    await expect(guard(createRoute('/'))).resolves.toBe('/reservation/orders')
  })

  it('ignores root login redirects after authentication', async () => {
    const guard = createAuthGuard(() => createAuthStoreForGuard())

    await expect(
      guard(
        createRoute(
          '/login',
          {
            public: true,
          },
          {
            name: 'login',
            query: {
              redirect: '/',
            },
          },
        ),
      ),
    ).resolves.toBe('/reservation/orders')
  })
})
