import { computed, ref } from 'vue'

import {
  fetchBootstrapBackendStatus,
  fetchBootstrapState,
  saveBootstrapConfig,
  startBootstrapBackend,
  testBootstrapDatabase,
  testBootstrapRuntime
} from '../services/bootstrap.js'
import {
  fetchCurrentAuthUser,
  login as loginByAccount
} from '../services/auth.js'
import { setRuntimeApiBaseUrl } from '../services/api.js'
import { checkBackendHealth } from './useBackendHealth.js'
import { resolveDefaultAuthorizedRoute } from '../utils/accessControl.js'
import { useToast } from './useToast.js'
import { fetchSettings } from '../services/settings.js'
import { setThemeSkin } from './useThemeSkin.js'
import { normalizeAuthUserSnapshot, resolveAuthUserAdminFlag } from '../utils/authUser.js'
import {
  AUTH_SESSION_EXPIRED_EVENT,
  clearAuthCredentials,
  hasValidAuthSession,
  persistAuthCredentials,
  readAuthAccessToken,
  readAuthExpiresAt
} from '../utils/authSessionStorage.js'
import {
  clearAuthSessionMetrics,
  finalizeAndRevokeAuthSession,
  finalizeAuthSession,
  incrementAuthActivityCount,
  persistAuthSessionMetrics
} from '../utils/authSessionMetrics.js'

const AUTH_USER_KEY = 'x-financial-auth-user'
const AUTH_LAST_ACTIVITY_KEY = 'x-financial-auth-last-activity'
const DEFAULT_USER_NAME = '系统管理员'
const DEFAULT_USER_ROLE = '管理员'
const SESSION_ACTIVITY_EVENTS = ['pointerdown', 'keydown', 'scroll', 'touchstart', 'visibilitychange']
const authIdleTimeoutMinutes = Number(import.meta.env.VITE_AUTH_IDLE_TIMEOUT_MINUTES || 30)
const authIdleTimeoutMs =
  Number.isFinite(authIdleTimeoutMinutes) && authIdleTimeoutMinutes > 0
    ? authIdleTimeoutMinutes * 60 * 1000
    : 30 * 60 * 1000

function resolveBrowserApiBaseUrl() {
  return '/api/v1'
}

let sessionRouter = null
let sessionTimeoutHandle = 0
let sessionMonitoringInstalled = false
let lastActivityWriteAt = 0

function readClientBootstrapState() {
  const env = import.meta.env

  return {
    initialized: String(env.VITE_SETUP_COMPLETED || '').toLowerCase() === 'true',
    company: {
      name: env.VITE_COMPANY_NAME || '',
      code: env.VITE_COMPANY_CODE || '',
      admin_email: env.VITE_ADMIN_EMAIL || ''
    },
    web: {
      host: env.VITE_WEB_HOST || '0.0.0.0',
      port: Number(env.VITE_WEB_PORT || 5273)
    },
    server: {
      host: env.VITE_SERVER_HOST || '0.0.0.0',
      port: Number(env.VITE_SERVER_PORT || 8000)
    },
    database: {
      driver: 'postgresql',
      host: env.VITE_POSTGRES_HOST || '127.0.0.1',
      port: Number(env.VITE_POSTGRES_PORT || 5432),
      name: env.VITE_POSTGRES_DB || 'x_financial',
      username: env.VITE_POSTGRES_USER || 'postgres',
      password_configured: false
    },
    redis: {
      enabled: Boolean(env.VITE_REDIS_URL),
      url: env.VITE_REDIS_URL || ''
    }
  }
}

function readAuthState() {
  return hasValidAuthSession()
}

function buildAnonymousUser() {
  return {
    username: '',
    tenantId: '',
    name: '',
    role: '',
    department: '',
    departmentName: '',
    position: '',
    grade: '',
    employeeNo: '',
    managerName: '',
    location: '',
    costCenter: '',
    financeOwnerName: '',
    riskProfile: {},
    roleCodes: [],
    email: '',
    avatar: '',
    isAdmin: false
  }
}

function resolvePlatformAdminFlag(payload, roleCodes = []) {
  return resolveAuthUserAdminFlag(payload, roleCodes)
}

function normalizeStoredAuthUser(payload = {}) {
  const user = normalizeAuthUserSnapshot(payload, {
    defaultName: DEFAULT_USER_NAME,
    defaultRole: DEFAULT_USER_ROLE
  })

  return {
    ...user,
    isAdmin: resolvePlatformAdminFlag(payload, user.roleCodes)
  }
}

function readStoredUser() {
  if (typeof window === 'undefined') {
    return buildAnonymousUser()
  }

  const raw = window.sessionStorage.getItem(AUTH_USER_KEY)

  if (raw) {
    try {
      const payload = JSON.parse(raw)
      if (payload && typeof payload === 'object') {
        return normalizeStoredAuthUser(payload)
      }
    } catch {
      return buildAnonymousUser()
    }
  }

  return buildAnonymousUser()
}

function readLastActivityAt() {
  if (typeof window === 'undefined') {
    return 0
  }

  return Number(window.sessionStorage.getItem(AUTH_LAST_ACTIVITY_KEY) || 0)
}

function isSessionExpired(now = Date.now()) {
  if (!readAuthAccessToken()) {
    return false
  }

  if (!hasValidAuthSession(now)) {
    return true
  }

  const lastActivityAt = readLastActivityAt()

  if (!lastActivityAt) {
    return true
  }

  return now - lastActivityAt > authIdleTimeoutMs
}

function persistAuthState(value, user = null, sessionId = '', accessToken = '', expiresAt = '') {
  if (typeof window === 'undefined') {
    return
  }

  if (value) {
    const normalizedUser = user || buildAnonymousUser()
    window.sessionStorage.setItem(AUTH_USER_KEY, JSON.stringify(normalizedUser))
    persistAuthCredentials(accessToken, expiresAt)
    persistAuthSessionMetrics(sessionId)
    return
  }

  window.sessionStorage.removeItem(AUTH_USER_KEY)
  window.sessionStorage.removeItem(AUTH_LAST_ACTIVITY_KEY)
  window.sessionStorage.removeItem('x-financial-authenticated')
  window.sessionStorage.removeItem('x-financial-auth-username')
  clearAuthCredentials()
  clearAuthSessionMetrics()
}

function persistAuthUserSnapshot(user = {}) {
  if (typeof window === 'undefined') {
    return
  }

  const normalizedUser = user || buildAnonymousUser()
  window.sessionStorage.setItem(AUTH_USER_KEY, JSON.stringify(normalizedUser))
}

function clearSessionTimeout() {
  if (typeof window === 'undefined' || !sessionTimeoutHandle) {
    return
  }

  window.clearTimeout(sessionTimeoutHandle)
  sessionTimeoutHandle = 0
}

function redirectToLogin() {
  if (sessionRouter?.currentRoute?.value?.name === 'login') {
    return
  }

  if (sessionRouter) {
    sessionRouter.replace({ name: 'login' })
    return
  }

  if (typeof window !== 'undefined' && window.location.pathname !== '/login') {
    window.location.assign('/login')
  }
}

function scheduleSessionTimeout() {
  clearSessionTimeout()

  if (typeof window === 'undefined' || !readAuthState()) {
    return
  }

  const lastActivityAt = readLastActivityAt()

  if (!lastActivityAt) {
    return
  }

  const idleRemaining = authIdleTimeoutMs - (Date.now() - lastActivityAt)
  const tokenRemaining = readAuthExpiresAt() - Date.now()
  const remaining = Math.min(idleRemaining, tokenRemaining)

  if (remaining <= 0) {
    logout('timeout', { notify: true })
    return
  }

  sessionTimeoutHandle = window.setTimeout(() => {
    logout('timeout', { notify: true })
  }, remaining)
}

function touchAuthActivity(force = false) {
  if (typeof window === 'undefined' || !readAuthState()) {
    return
  }

  const now = Date.now()

  if (!force && now - lastActivityWriteAt < 1000) {
    scheduleSessionTimeout()
    return
  }

  window.sessionStorage.setItem(AUTH_LAST_ACTIVITY_KEY, String(now))
  incrementAuthActivityCount()
  lastActivityWriteAt = now
  scheduleSessionTimeout()
}

function handleSessionActivity(event) {
  if (typeof document !== 'undefined' && event?.type === 'visibilitychange' && document.visibilityState !== 'visible') {
    return
  }

  touchAuthActivity()
}

function handleAuthSessionExpired() {
  if (!readAuthAccessToken()) {
    return
  }
  logout('expired', { notify: true, revoke: false })
}

function handleSessionUnload(event) {
  if (event?.type === 'pagehide' && event.persisted) {
    return
  }
  finalizeAuthSession('pagehide', { unload: true })
}

function installSessionMonitoring() {
  if (sessionMonitoringInstalled || typeof window === 'undefined') {
    return
  }

  sessionMonitoringInstalled = true
  SESSION_ACTIVITY_EVENTS.forEach((eventName) => {
    window.addEventListener(eventName, handleSessionActivity, { passive: true })
  })
  window.addEventListener(AUTH_SESSION_EXPIRED_EVENT, handleAuthSessionExpired)
  window.addEventListener('pagehide', handleSessionUnload, { passive: true })
  window.addEventListener('beforeunload', handleSessionUnload, { passive: true })
}

function syncAuthSession(options = {}) {
  const shouldNotify = Boolean(options.notify)

  if (!readAuthState()) {
    loggedIn.value = false
    currentUser.value = buildAnonymousUser()
    clearSessionTimeout()
    return false
  }

  if (isSessionExpired()) {
    logout('timeout', { notify: shouldNotify, redirect: false })
    return false
  }

  loggedIn.value = true
  currentUser.value = readStoredUser()
  scheduleSessionTimeout()
  return true
}

async function refreshCurrentUserFromBackend(options = {}) {
  if (!readAuthState()) {
    return false
  }

  try {
    const payload = await fetchCurrentAuthUser()
    const user = normalizeStoredAuthUser(payload)
    currentUser.value = user
    persistAuthUserSnapshot(user)
    return true
  } catch (error) {
    if (!options.silent) {
      toast(error.message || '当前用户信息刷新失败，请重新登录后再试。')
    }
    console.warn('Failed to refresh current user snapshot:', error)
    return false
  }
}

function reconcileEntryRoute(router) {
  const target = resolveEntryRoute()
  const current = router.currentRoute.value

  if (!current.name || current.name === 'root' || current.name === 'setup' || target.name === 'setup') {
    router.replace(target)
  }
}

export function installSessionNavigation(router) {
  sessionRouter = router
  installSessionMonitoring()

  if (readAuthState() && !isSessionExpired()) {
    scheduleSessionTimeout()
  }

  fetchBootstrapState()
    .then((state) => {
      applyBootstrapState(state)
      setRuntimeApiBaseUrl(resolveBrowserApiBaseUrl(state))
      if (loggedIn.value) {
        refreshCurrentUserFromBackend({ silent: true })
      }
      fetchSettings()
        .then((snapshot) => {
          if (snapshot?.appearanceForm?.themeSkin) {
            setThemeSkin(snapshot.appearanceForm.themeSkin)
          }
        })
        .catch((error) => {
          console.warn('Failed to load remote theme settings:', error)
        })
      router.isReady().then(() => reconcileEntryRoute(router))
    })
    .catch(() => {
      router.isReady().then(() => {
        if (!isInitialized.value && router.currentRoute.value.name !== 'setup') {
          router.replace({ name: 'setup' })
        }
      })
    })
}

const bootstrapState = ref(readClientBootstrapState())
const setupSubmitting = ref(false)
const setupError = ref('')
const setupProgressMessage = ref('')
const setupStartupVisible = ref(false)
const setupStartupSteps = ref([])
const setupStartupLog = ref('')
const setupCountdownSeconds = ref(0)
const runtimeTesting = ref(false)
const databaseTesting = ref(false)
const runtimeTestPassed = ref(false)
const databaseTestPassed = ref(false)
const runtimeTestMessage = ref('')
const databaseTestMessage = ref('')
const loginSubmitting = ref(false)
const loginError = ref('')
const loggedIn = ref(readAuthState() && !isSessionExpired())
const currentUser = ref(readStoredUser())

if (!loggedIn.value && readAuthAccessToken()) {
  persistAuthState(false)
}

const { toast } = useToast()

const companyProfile = computed(() => ({
  name: bootstrapState.value.company?.name || '',
  code: bootstrapState.value.company?.code || '',
  adminEmail: bootstrapState.value.company?.admin_email || '',
  logo: bootstrapState.value.company?.logo || ''
}))

function updateCompanyProfilePreview(payload = {}) {
  const currentCompany = bootstrapState.value.company || {}

  bootstrapState.value = {
    ...bootstrapState.value,
    company: {
      ...currentCompany,
      ...(payload.name !== undefined ? { name: payload.name } : {}),
      ...(payload.code !== undefined ? { code: payload.code } : {}),
      ...(payload.adminEmail !== undefined ? { admin_email: payload.adminEmail } : {}),
      ...(payload.logo !== undefined ? { logo: payload.logo } : {})
    }
  }
}

const isInitialized = computed(() => Boolean(bootstrapState.value.initialized))

function applyBootstrapState(state) {
  bootstrapState.value = state

  if (!state.initialized) {
    logout('reset', { redirect: false })
  }
}

function clearSetupRuntimeState() {
  runtimeTesting.value = false
  databaseTesting.value = false
  runtimeTestPassed.value = false
  databaseTestPassed.value = false
  runtimeTestMessage.value = ''
  databaseTestMessage.value = ''
  setupError.value = ''
  setupProgressMessage.value = ''
  setupStartupVisible.value = false
  setupStartupSteps.value = []
  setupStartupLog.value = ''
  setupCountdownSeconds.value = 0
}

function resetFromClientEnv() {
  applyBootstrapState(readClientBootstrapState())
  clearSetupRuntimeState()
  loginError.value = ''
  currentUser.value = readStoredUser()
}

function sleep(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms))
}

function applyBackendStartupStatus(status) {
  setupStartupVisible.value = true
  setupStartupSteps.value = Array.isArray(status?.steps) ? status.steps : []
  setupStartupLog.value = status?.logTail || ''
  setupProgressMessage.value = status?.detail || setupProgressMessage.value
}

async function waitForBackendStartup() {
  const started = await startBootstrapBackend()
  applyBackendStartupStatus(started)

  while (true) {
    const status = await fetchBootstrapBackendStatus()
    applyBackendStartupStatus(status)

    if (status?.completed) {
      return status
    }

    if (status?.failed) {
      throw new Error(status.detail || 'FastAPI 后端启动失败。')
    }

    await sleep(1000)
  }
}

async function runLoginCountdown() {
  for (let second = 5; second > 0; second -= 1) {
    setupCountdownSeconds.value = second
    setupProgressMessage.value = `配置成功，${second} 秒后进入登录页...`
    await sleep(1000)
  }
}

async function handleSetupSubmit(payload) {
  if (!runtimeTestPassed.value) {
    setupError.value = '请先完成运行端口检测。'
    toast(setupError.value)
    return false
  }

  if (!databaseTestPassed.value) {
    setupError.value = '请先完成数据库连接检测。'
    toast(setupError.value)
    return false
  }

  setupSubmitting.value = true
  setupError.value = ''
  setupProgressMessage.value = '正在写入初始化配置...'
  setupStartupVisible.value = true
  setupStartupSteps.value = [
    { id: 'config', label: '第一步：写入初始化配置', status: 'running', detail: '正在保存企业、管理员、端口和数据库配置。' },
    { id: 'deps', label: '第二步：安装/检查后端虚拟环境', status: 'pending', detail: '等待后端启动任务开始。' },
    { id: 'server', label: '第三步：启动 FastAPI 服务', status: 'pending', detail: '等待启动 uvicorn。' },
    { id: 'health', label: '第四步：检测后端健康状态', status: 'pending', detail: '等待 /api/v1/health。' },
    { id: 'done', label: '第五步：配置完成', status: 'pending', detail: '后端就绪后进入登录页。' }
  ]
  setupStartupLog.value = ''
  setupCountdownSeconds.value = 0

  try {
    const state = await saveBootstrapConfig(payload)
    setupStartupSteps.value = setupStartupSteps.value.map((step) =>
      step.id === 'config'
        ? { ...step, status: 'success', detail: '初始化配置已写入。' }
        : step
    )
    setupProgressMessage.value = '配置已写入，正在启动 FastAPI 后端...'
    await waitForBackendStartup()
    setRuntimeApiBaseUrl(resolveBrowserApiBaseUrl(state))
    setupProgressMessage.value = '后端已启动，正在检测服务连通性...'

    const backendReady = await checkBackendHealth({ force: true })

    if (!backendReady) {
      throw new Error('FastAPI 后端已启动，但浏览器暂时无法连接后端接口。请确认 Server Host 使用 0.0.0.0，且防火墙允许访问后端端口。')
    }

    setupStartupSteps.value = setupStartupSteps.value.map((step) =>
      step.id === 'done'
        ? { ...step, status: 'success', detail: '配置成功，准备进入登录页。' }
        : step
    )
    setupProgressMessage.value = '配置成功，准备进入登录页...'
    applyBootstrapState(state)
    toast('初始化完成，后端已启动。')
    await runLoginCountdown()
    return true
  } catch (error) {
    setupError.value = error.message || '初始化配置写入或后端启动失败，请稍后重试。'
    setupStartupVisible.value = true
    setupStartupSteps.value = setupStartupSteps.value.map((step) =>
      step.id === 'done'
        ? { ...step, status: 'error', detail: setupError.value }
        : step
    )
    toast(setupError.value)
    return false
  } finally {
    setupSubmitting.value = false
  }
}

async function handleRuntimeTest(payload) {
  runtimeTesting.value = true
  runtimeTestMessage.value = ''
  setupError.value = ''

  try {
    const result = await testBootstrapRuntime(payload)
    runtimeTestPassed.value = true
    runtimeTestMessage.value = result.detail || '端口占用检测通过。'
    toast(runtimeTestMessage.value)
  } catch (error) {
    runtimeTestPassed.value = false
    runtimeTestMessage.value = error.message || '端口占用检测失败。'
    toast(runtimeTestMessage.value)
  } finally {
    runtimeTesting.value = false
  }
}

async function handleDatabaseTest(payload) {
  databaseTesting.value = true
  databaseTestMessage.value = ''
  setupError.value = ''

  try {
    const result = await testBootstrapDatabase(payload)
    databaseTestPassed.value = true
    databaseTestMessage.value = result.detail || '数据库连接检测通过。'
    toast(databaseTestMessage.value)
  } catch (error) {
    databaseTestPassed.value = false
    databaseTestMessage.value = error.message || '数据库连接检测失败。'
    toast(databaseTestMessage.value)
  } finally {
    databaseTesting.value = false
  }
}

function handleRuntimeDirty() {
  runtimeTestPassed.value = false
  runtimeTestMessage.value = ''

  if (setupError.value === '请先完成运行端口检测。') {
    setupError.value = ''
  }
}

function handleDatabaseDirty() {
  databaseTestPassed.value = false
  databaseTestMessage.value = ''

  if (setupError.value === '请先完成数据库连接检测。') {
    setupError.value = ''
  }
}

async function handleLogin(credentials) {
  loginSubmitting.value = true
  loginError.value = ''

  try {
    const response = await loginByAccount({
      username: credentials.username,
      password: credentials.password,
      tenantId: credentials.tenantId
    })

    const responseUser = normalizeStoredAuthUser(response?.user || buildAnonymousUser())
    const responseRoleCodes = responseUser.roleCodes
    const user = {
      ...responseUser,
      roleCodes: responseRoleCodes,
      isAdmin: resolvePlatformAdminFlag(responseUser, responseRoleCodes)
    }
    loggedIn.value = true
    persistAuthState(
      true,
      user,
      response?.sessionId || '',
      response?.accessToken || '',
      response?.expiresAt || ''
    )
    currentUser.value = user
    touchAuthActivity(true)
    return true
  } catch (error) {
    logout('invalid', { redirect: false })
    loginError.value = error.message || '登录失败，请检查账号和密码。'
    toast(loginError.value)
    return false
  } finally {
    loginSubmitting.value = false
  }
}

function logout(reason = 'manual', options = {}) {
  const notify = options.notify ?? reason === 'timeout'
  const redirect = options.redirect ?? reason !== 'invalid'
  const revoke = options.revoke ?? (reason !== 'invalid' && reason !== 'expired')

  if (revoke && readAuthAccessToken()) {
    finalizeAndRevokeAuthSession(reason).catch((error) => {
      console.warn('Failed to revoke auth session:', error)
    })
  }
  loggedIn.value = false
  persistAuthState(false)
  currentUser.value = buildAnonymousUser()
  clearSessionTimeout()

  if (notify) {
    toast(
      reason === 'timeout' || reason === 'expired'
        ? '登录已失效，请重新登录。'
        : '已退出登录。'
    )
  }

  if (redirect) {
    redirectToLogin()
  }
}

function handleRecoverPassword() {
  toast('请联系系统管理员重置账号密码。')
}

function handleSsoLogin() {
  toast('SSO 登录暂未启用。')
}

function resolveEntryRoute() {
  loggedIn.value = syncAuthSession()
  currentUser.value = readStoredUser()

  if (!isInitialized.value) {
    return { name: 'setup' }
  }

  if (!loggedIn.value) {
    return { name: 'login' }
  }

  return resolveDefaultAuthorizedRoute(currentUser.value)
}

export function useSystemState() {
  return {
    bootstrapState,
    companyProfile,
    currentUser,
    databaseTestMessage,
    databaseTestPassed,
    databaseTesting,
    handleDatabaseDirty,
    handleDatabaseTest,
    handleLogin,
    handleRecoverPassword,
    handleRuntimeDirty,
    handleRuntimeTest,
    handleSetupSubmit,
    handleSsoLogin,
    isInitialized,
    loggedIn,
    loginError,
    loginSubmitting,
    logout,
    resetFromClientEnv,
    refreshCurrentUserFromBackend,
    resolveEntryRoute,
    runtimeTestMessage,
    runtimeTestPassed,
    runtimeTesting,
    setupError,
    setupCountdownSeconds,
    setupProgressMessage,
    setupStartupLog,
    setupStartupSteps,
    setupStartupVisible,
    setupSubmitting,
    syncAuthSession,
    updateCompanyProfilePreview
  }
}
