import { createPinia, setActivePinia } from 'pinia'
import { beforeEach, describe, expect, it, vi } from 'vitest'

import { ApiError } from '@/services/httpClient'
import { useAuthStore } from '@/stores/authStore'

vi.mock('@/services/authService', async (importOriginal) => {
  const actual = await importOriginal<typeof import('@/services/authService')>()
  return {
    ...actual,
    fetchCurrentAuth: vi.fn(),
    loginAuth: vi.fn(),
    logoutAuth: vi.fn(),
  }
})

const authService = await import('@/services/authService')

function createAuthPayload(overrides: Record<string, unknown> = {}) {
  return {
    access_token: 'session-token',
    token_type: 'Bearer',
    expires_at: '2026-07-09T12:00:00Z',
    user: {
      id: '1900000000000000001',
      username: 'admin',
      display_name: '系统管理员',
      super_admin: true,
    },
    default_hotel_id: 'HOTEL-TEST',
    hotels: [
      {
        hotel_id: 'HOTEL-TEST',
        hotel_name: '测试酒店',
        time_zone: 'Asia/Bangkok',
        default_hotel: true,
      },
      {
        hotel_id: 'HOTEL-BKK',
        hotel_name: '曼谷酒店',
        time_zone: 'Asia/Bangkok',
        default_hotel: false,
      },
    ],
    permissions: ['RESERVATION_ORDER_READ', 'HOTEL_SWITCH'],
    menus: [
      {
        menu_code: 'RESERVATION_ORDERS',
        menu_name: '订单列表',
        route_path: '/reservation/orders',
        component_key: 'ReservationOrders',
        icon_key: 'pi pi-list',
        permission_code: 'RESERVATION_ORDER_READ',
        sort_order: 10,
      },
    ],
    ...overrides,
  }
}

describe('authStore', () => {
  beforeEach(() => {
    setActivePinia(createPinia())
    vi.mocked(authService.fetchCurrentAuth).mockReset()
    vi.mocked(authService.loginAuth).mockReset()
    vi.mocked(authService.logoutAuth).mockReset()
    sessionStorage.clear()
    localStorage.clear()
  })

  it('stores login token only in sessionStorage and applies default hotel context', async () => {
    vi.mocked(authService.loginAuth).mockResolvedValue(createAuthPayload())
    const store = useAuthStore()

    await store.login({
      username: 'admin',
      password: 'Admin@123456',
    })

    expect(sessionStorage.getItem('th_hotel_access_token')).toBe('session-token')
    expect(localStorage.getItem('th_hotel_access_token')).toBeNull()
    expect(store.user?.username).toBe('admin')
    expect(store.selectedHotelId).toBe('HOTEL-TEST')
    expect(store.hasPermission('RESERVATION_ORDER_READ')).toBe(true)
  })

  it('restores auth state from an existing session token through auth me', async () => {
    vi.mocked(authService.fetchCurrentAuth).mockResolvedValue(createAuthPayload({ access_token: undefined }))
    sessionStorage.setItem('th_hotel_access_token', 'session-token')
    const store = useAuthStore()

    const restored = await store.restoreFromSession()

    expect(restored).toBe(true)
    expect(authService.fetchCurrentAuth).toHaveBeenCalledOnce()
    expect(store.user?.display_name).toBe('系统管理员')
    expect(store.selectedHotelId).toBe('HOTEL-TEST')
  })

  it('skips root and login placeholders when resolving the first menu path', async () => {
    vi.mocked(authService.loginAuth).mockResolvedValue(
      createAuthPayload({
        menus: [
          {
            menu_code: 'HOME_PLACEHOLDER',
            menu_name: '首页占位',
            route_path: '/',
            component_key: null,
            icon_key: 'pi pi-home',
            permission_code: null,
            sort_order: 1,
          },
          {
            menu_code: 'LOGIN_PLACEHOLDER',
            menu_name: '登录占位',
            route_path: '/login',
            component_key: null,
            icon_key: 'pi pi-sign-in',
            permission_code: null,
            sort_order: 2,
          },
          {
            menu_code: 'RESERVATION_TASKS',
            menu_name: '任务队列',
            route_path: '/reservation/tasks',
            component_key: 'ReservationTasks',
            icon_key: 'pi pi-check-square',
            permission_code: 'RESERVATION_TASK_READ',
            sort_order: 3,
          },
        ],
      }),
    )
    const store = useAuthStore()

    await store.login({
      username: 'admin',
      password: 'Admin@123456',
    })

    expect(store.visibleMenus.map((menu) => menu.menu_code)).toEqual(['RESERVATION_TASKS'])
    expect(store.firstMenuPath).toBe('/reservation/tasks')
  })

  it('clears token and user context when the auth session is invalid', async () => {
    vi.mocked(authService.fetchCurrentAuth).mockRejectedValue(
      new ApiError('登录已失效。', 401, {
        error_code: 'AUTH_SESSION_INVALID',
        message: '登录已失效。',
      }),
    )
    sessionStorage.setItem('th_hotel_access_token', 'expired-token')
    const store = useAuthStore()

    const restored = await store.restoreFromSession()

    expect(restored).toBe(false)
    expect(sessionStorage.getItem('th_hotel_access_token')).toBeNull()
    expect(store.user).toBeNull()
    expect(store.permissions).toEqual([])
  })

  it('keeps the session token when auth restore fails for a transient backend error', async () => {
    vi.mocked(authService.fetchCurrentAuth).mockRejectedValue(
      new ApiError('Server error', 500, {
        error_code: 'AUTH_TEMPORARY_UNAVAILABLE',
        message: '认证服务暂不可用。',
      }),
    )
    sessionStorage.setItem('th_hotel_access_token', 'session-token')
    const store = useAuthStore()

    const restored = await store.restoreFromSession()

    expect(restored).toBe(false)
    expect(sessionStorage.getItem('th_hotel_access_token')).toBe('session-token')
    expect(store.accessToken).toBe('session-token')
    expect(store.user).toBeNull()
    expect(store.restoreAttempted).toBe(false)
  })

  it('clears local auth context even when backend logout fails', async () => {
    vi.mocked(authService.loginAuth).mockResolvedValue(createAuthPayload())
    vi.mocked(authService.logoutAuth).mockRejectedValue(new Error('network down'))
    const store = useAuthStore()
    await store.login({
      username: 'admin',
      password: 'Admin@123456',
    })

    await expect(store.logout()).resolves.toBeUndefined()

    expect(sessionStorage.getItem('th_hotel_access_token')).toBeNull()
    expect(store.user).toBeNull()
    expect(store.permissions).toEqual([])
  })
})
