import { defineStore } from 'pinia'

import { fetchCurrentAuth, loginAuth, logoutAuth } from '@/services/authService'
import { clearStoredAccessToken, getStoredAccessToken, setStoredAccessToken } from '@/services/authSession'
import { isAuthUnauthorizedError } from '@/services/httpClient'
import type {
  AuthHotelResult,
  AuthLoginRequest,
  AuthLoginResult,
  AuthMeResult,
  AuthMenuResult,
  AuthPermissionCode,
  AuthUserResult,
} from '@/types/auth'
import { normalizeAuthenticatedRoutePath } from '@/utils/authNavigation'

interface AuthState {
  accessToken: string | null
  user: AuthUserResult | null
  defaultHotelId: string | null
  hotels: AuthHotelResult[]
  permissions: AuthPermissionCode[]
  menus: AuthMenuResult[]
  selectedHotelId: string | null
  restoreAttempted: boolean
  restoring: boolean
}

export const useAuthStore = defineStore('auth', {
  state: (): AuthState => ({
    accessToken: getStoredAccessToken(),
    user: null,
    defaultHotelId: null,
    hotels: [],
    permissions: [],
    menus: [],
    selectedHotelId: null,
    restoreAttempted: false,
    restoring: false,
  }),
  getters: {
    isAuthenticated: (state) => Boolean(state.accessToken && state.user),
    selectedHotel: (state) =>
      state.hotels.find((hotel) => hotel.hotel_id === state.selectedHotelId) ?? state.hotels[0] ?? null,
    visibleMenus: (state) =>
      [...state.menus]
        .filter((menu) => normalizeAuthenticatedRoutePath(menu.route_path))
        .sort((left, right) => (left.sort_order ?? 0) - (right.sort_order ?? 0)),
    firstMenuPath(): string | null {
      return this.visibleMenus[0]?.route_path ?? null
    },
  },
  actions: {
    hasPermission(permission: AuthPermissionCode): boolean {
      return this.permissions.includes(permission)
    },
    hasStoredToken(): boolean {
      return Boolean(getStoredAccessToken())
    },
    async login(request: AuthLoginRequest): Promise<AuthLoginResult> {
      const result = await loginAuth(request)
      this.applyLoginResult(result)
      return result
    },
    async restoreFromSession(): Promise<boolean> {
      if (this.restoreAttempted && this.isAuthenticated) {
        return true
      }
      const token = getStoredAccessToken()
      if (!token) {
        this.clearAuth()
        this.restoreAttempted = true
        return false
      }

      this.accessToken = token
      this.restoring = true
      try {
        const result = await fetchCurrentAuth()
        this.applyAuthContext(result)
        this.restoreAttempted = true
        return true
      } catch (error) {
        if (isAuthUnauthorizedError(error)) {
          this.clearAuth()
          this.restoreAttempted = true
        } else {
          this.accessToken = token
          this.restoreAttempted = false
        }
        return false
      } finally {
        this.restoring = false
      }
    },
    async logout(): Promise<void> {
      try {
        if (this.accessToken) {
          await logoutAuth()
        }
      } catch {
        // 本地退出必须完成；后端登出失败时不保留过期 token 或用户上下文。
      } finally {
        this.clearAuth()
        this.restoreAttempted = true
      }
    },
    applyLoginResult(result: AuthLoginResult): void {
      this.accessToken = result.access_token
      setStoredAccessToken(result.access_token)
      this.applyAuthContext(result)
      this.restoreAttempted = true
    },
    applyAuthContext(result: AuthMeResult): void {
      this.user = result.user
      this.defaultHotelId = result.default_hotel_id
      this.hotels = result.hotels
      this.permissions = result.permissions
      this.menus = result.menus
      this.selectedHotelId = resolveSelectedHotelId(result.hotels, result.default_hotel_id, this.selectedHotelId)
    },
    setSelectedHotelId(hotelId: string): void {
      if (this.hotels.some((hotel) => hotel.hotel_id === hotelId)) {
        this.selectedHotelId = hotelId
      }
    },
    clearAuth(): void {
      clearStoredAccessToken()
      this.accessToken = null
      this.user = null
      this.defaultHotelId = null
      this.hotels = []
      this.permissions = []
      this.menus = []
      this.selectedHotelId = null
      this.restoring = false
    },
  },
})

function resolveSelectedHotelId(
  hotels: AuthHotelResult[],
  defaultHotelId: string | null,
  currentHotelId: string | null,
): string | null {
  if (currentHotelId && hotels.some((hotel) => hotel.hotel_id === currentHotelId)) {
    return currentHotelId
  }
  if (defaultHotelId && hotels.some((hotel) => hotel.hotel_id === defaultHotelId)) {
    return defaultHotelId
  }
  return hotels.find((hotel) => hotel.default_hotel)?.hotel_id ?? hotels[0]?.hotel_id ?? null
}
