import {
  ContainerOutlined,
  LogoutOutlined,
  ShoppingOutlined,
  UserOutlined,
} from '@ant-design/icons'
import { App, Button, Layout, Menu, Typography } from 'antd'
import { useQueryClient } from '@tanstack/react-query'
import type { MenuProps } from 'antd'
import { Outlet, useLocation, useNavigate } from 'react-router'

import { logoutWorker } from '@/services/worker'
import { useIsMobile } from '@/utils/use-is-mobile'
import { clearWorkerSession, getWorkerStatus, getWorkerUsername } from '@/utils/worker-auth'
import { getWorkerToken } from '@/utils/worker-auth'
import { useRealtimeEvents, type RealtimeEvent } from '@/hooks/useRealtimeEvents'
import WorkerAnnouncementBanner from '@/components/worker/WorkerAnnouncementBanner'

const menuItems: MenuProps['items'] = [
  { key: '/hall', icon: <ShoppingOutlined />, label: '抢单大厅' },
  { key: '/orders', icon: <ContainerOutlined />, label: '我的订单' },
  { key: '/profile', icon: <UserOutlined />, label: '个人中心' },
]

const tabItems = [
  { key: '/hall', icon: ShoppingOutlined, label: '抢单大厅' },
  { key: '/orders', icon: ContainerOutlined, label: '我的订单' },
  { key: '/profile', icon: UserOutlined, label: '个人中心' },
]

export default function WorkerLayout() {
  const navigate = useNavigate()
  const location = useLocation()
  const isMobile = useIsMobile()
  const { message, modal } = App.useApp()
  const queryClient = useQueryClient()
  const username = getWorkerUsername() || '打手'
  const status = getWorkerStatus()
  const currentKey = resolveSelectedKey(location.pathname)

  useRealtimeEvents({
    url: '/api/v1/worker/realtime',
    token: getWorkerToken(),
    onEvent: (event) => applyWorkerRealtimeEvent(event, queryClient),
  })

  async function submitLogout() {
    try {
      await logoutWorker()
    } catch {
      // 接单端退出为无状态操作，本地清理优先。
    } finally {
      clearWorkerSession()
      message.success('已退出登录')
      void navigate('/', { replace: true })
    }
  }

  function confirmLogout() {
    modal.confirm({
      title: '确认退出登录',
      content: '退出后需要重新登录才能继续抢单和处理订单。',
      okText: '确认退出',
      cancelText: '取消',
      okButtonProps: { danger: true },
      onOk: submitLogout,
    })
  }

  if (isMobile) {
    return (
      <div className="worker-mobile-shell">
        <header className="worker-mobile-header">
          <div className="worker-mobile-brand">
            <span className="worker-mobile-brand-badge">锤</span>
            <div className="worker-mobile-brand-text">
              <strong>王大锤接单</strong>
            </div>
          </div>
          <div className="worker-mobile-user-area">
            <Button
              type="text"
              size="small"
              icon={<LogoutOutlined />}
              className="worker-mobile-logout-btn"
              onClick={confirmLogout}
              title="退出登录"
            />
          </div>
        </header>

        <main className="worker-mobile-content">
          <WorkerAnnouncementBanner />
          <Outlet />
        </main>

        <nav className="worker-mobile-tabbar" aria-label="移动端底部导航">
          {tabItems.map((item) => {
            const Icon = item.icon
            const isActive = currentKey === item.key
            return (
              <button
                key={item.key}
                type="button"
                className={`worker-mobile-tab-item ${isActive ? 'active' : ''}`}
                onClick={() => navigate(item.key)}
              >
                <div className="worker-mobile-tab-icon">
                  <Icon />
                </div>
                <span className="worker-mobile-tab-label">{item.label}</span>
              </button>
            )
          })}
        </nav>
      </div>
    )
  }

  return (
    <Layout className="admin-shell worker-shell">
      <Layout.Sider width={220} className="admin-sider" trigger={null}>
        <div className="admin-sider-inner">
          <div className="admin-brand">
            <div className="admin-brand-copy">
              <strong>王大锤</strong>
              <span>接单平台</span>
            </div>
          </div>
          <div className="admin-sidebar-profile">
            <Typography.Text strong>{username}</Typography.Text>
            <Typography.Text type="secondary">{formatWorkerStatus(status)}</Typography.Text>
          </div>
          <Menu
            mode="inline"
            inlineIndent={16}
            selectedKeys={[currentKey]}
            items={menuItems}
            className="admin-menu"
            onClick={({ key }) => navigate(String(key))}
          />
          <div className="admin-sider-footer">
            <Button block icon={<LogoutOutlined />} onClick={submitLogout}>
              退出登录
            </Button>
          </div>
        </div>
      </Layout.Sider>
      <Layout className="admin-main-shell">
        <Layout.Content className="admin-content">
          <WorkerAnnouncementBanner />
          <Outlet />
        </Layout.Content>
      </Layout>
    </Layout>
  )
}

function applyWorkerRealtimeEvent(
  event: RealtimeEvent,
  queryClient: ReturnType<typeof useQueryClient>,
) {
  if (event.type === 'work_order.changed' && isRecord(event.data)) {
    const data = event.data
    if (event.scopes.includes('worker_my_orders')) {
      patchWorkerMyOrderCaches(queryClient, { ...event, data })
      void queryClient.invalidateQueries({ queryKey: ['worker-after-sales-cases'] })
    }
    if (event.scopes.includes('worker_hall')) {
      patchWorkerHallCaches(queryClient, { ...event, data })
    }
  }

  if (event.type === 'worker_wallet.changed' && isRecord(event.data)) {
    const walletData = event.data
    queryClient.setQueryData(['worker-profile'], (current: unknown) => {
      if (!isRecord(current) || !isRecord(current.data) || !isRecord(current.data.worker))
        return current
      return {
        ...current,
        data: {
          ...current.data,
          worker: { ...current.data.worker, wallet: walletData.wallet || walletData },
        },
      }
    })
  }

  if (event.type === 'worker_finance_request.changed' && isRecord(event.data)) {
    const data = event.data
    queryClient.setQueriesData({ queryKey: ['worker-finance-requests'] }, (current: unknown) =>
      patchFinanceRequestListEnvelope(current, { ...event, data }),
    )
  }
}

function patchWorkerMyOrderCaches(
  queryClient: ReturnType<typeof useQueryClient>,
  event: RealtimeEvent,
) {
  for (const [queryKey, current] of queryClient.getQueriesData({
    queryKey: ['worker-my-orders'],
  })) {
    const status = String(queryKey[1] || '')
    const keyword = String(queryKey[2] || '')
    const page = Number(queryKey[3] || 1)
    const item = event.data as {
      status?: unknown
      productName?: unknown
      platformOrderId?: unknown
    }
    const matchesStatus = !status || status === String(item.status || '')
    const matchesKeyword = matchesWorkOrderKeyword(item, keyword)
    const matches = matchesStatus && matchesKeyword
    const shouldInsert = event.operation === 'upsert' && page === 1 && matches
    const operation = event.operation === 'remove' || !matches ? 'remove' : 'upsert'
    queryClient.setQueryData(
      queryKey,
      patchWorkOrderListEnvelope(current, { ...event, operation }, shouldInsert),
    )
  }
}

function patchWorkerHallCaches(
  queryClient: ReturnType<typeof useQueryClient>,
  event: RealtimeEvent,
) {
  if (event.operation === 'refresh') {
    void queryClient.resetQueries({ queryKey: ['worker-hall-orders'] })
    return
  }
  const workerSnapshot = applyWorkerDepositRule(queryClient, event.data)
  const item = workerSnapshot as {
    status?: unknown
    categoryId?: unknown
    productName?: unknown
    platformOrderId?: unknown
  }
  for (const [queryKey, current] of queryClient.getQueriesData({
    queryKey: ['worker-hall-orders'],
  })) {
    const keyword = String(queryKey[1] || '')
    const categoryId = Number(queryKey[2] || 0)
    const matchesCategory = !categoryId || categoryId === Number(item.categoryId || 0)
    const matches =
      String(item.status || '') === 'open' &&
      matchesCategory &&
      matchesWorkOrderKeyword(item, keyword)
    const shouldInsert = event.operation === 'upsert' && matches
    const operation = event.operation === 'remove' || !matches ? 'remove' : 'upsert'
    queryClient.setQueryData(
      queryKey,
      patchInfiniteWorkOrderEnvelope(
        current,
        { ...event, data: workerSnapshot, operation },
        shouldInsert,
      ),
    )
  }
}

function applyWorkerDepositRule(queryClient: ReturnType<typeof useQueryClient>, data: unknown) {
  if (!isRecord(data)) return data
  const profile = queryClient.getQueryData(['worker-profile'])
  const depositFreeAmount =
    isRecord(profile) && isRecord(profile.data) && isRecord(profile.data.worker)
      ? Number(
          (profile.data.worker.level as { permissions?: { depositFreeAmount?: unknown } } | null)
            ?.permissions?.depositFreeAmount || 0,
        )
      : 0
  const requiredDepositAmount = Number(data.requiredDepositAmount || 0)
  return {
    ...data,
    freezeDepositAmount: Math.max(0, requiredDepositAmount - depositFreeAmount),
  }
}

function matchesWorkOrderKeyword(
  item: { productName?: unknown; platformOrderId?: unknown; material?: unknown },
  keyword: string,
) {
  const normalizedKeyword = keyword.trim().toLowerCase()
  if (!normalizedKeyword) return true
  const material = isRecord(item.material) ? item.material : {}
  const collect = isRecord(material.collect) ? material.collect : {}
  const fields = isRecord(collect.fields) ? collect.fields : {}
  return [
    item.productName,
    item.platformOrderId,
    fields.gameId,
    fields.gameNickname,
    fields.gameAccount,
    fields.roleName,
    material.gameId,
    material.gameNickname,
  ]
    .map((value) => String(value || '').toLowerCase())
    .some((value) => value.includes(normalizedKeyword))
}

function patchWorkOrderListEnvelope(current: unknown, event: RealtimeEvent, insert = false) {
  if (!isRecord(current) || !isRecord(current.data) || !Array.isArray(current.data.items)) {
    return current
  }
  const id = Number((event.data as { workOrderId?: unknown }).workOrderId || event.entityId)
  const items = current.data.items as unknown[]
  const nextItems =
    event.operation === 'remove'
      ? items.filter((entry) => Number((entry as { workOrderId?: unknown })?.workOrderId) !== id)
      : upsertById(items, event.data, 'workOrderId', insert)
  return { ...current, data: { ...current.data, items: nextItems } }
}

function patchInfiniteWorkOrderEnvelope(current: unknown, event: RealtimeEvent, insert = false) {
  if (!isRecord(current) || !Array.isArray(current.pages)) return current
  return {
    ...current,
    pages: current.pages.map((page: unknown, index) =>
      patchWorkOrderListEnvelope(page, event, insert && index === 0),
    ),
  }
}

function patchFinanceRequestListEnvelope(current: unknown, event: RealtimeEvent) {
  if (!isRecord(current) || !isRecord(current.data) || !Array.isArray(current.data.items)) {
    return current
  }
  const id = Number((event.data as { requestId?: unknown }).requestId || event.entityId)
  const items = current.data.items as unknown[]
  const nextItems =
    event.operation === 'remove'
      ? items.filter((entry) => Number((entry as { requestId?: unknown })?.requestId) !== id)
      : upsertById(items, event.data, 'requestId')
  return { ...current, data: { ...current.data, items: nextItems } }
}

function upsertById(items: unknown[], nextItem: unknown, idKey: string, insert = false) {
  const id = Number((nextItem as Record<string, unknown>)[idKey] || 0)
  const index = items.findIndex(
    (item) => Number((item as Record<string, unknown>)?.[idKey] || 0) === id,
  )
  if (index < 0) return insert ? [nextItem, ...items] : items
  return items.map((item, itemIndex) => {
    if (itemIndex !== index) return item
    if (!isRecord(item) || !isRecord(nextItem)) return nextItem
    // 大厅广播是公共快照，合并后保留当前打手私有的 myShare 等字段。
    return { ...item, ...nextItem }
  })
}

function isRecord(value: unknown): value is Record<string, unknown> {
  return Boolean(value && typeof value === 'object' && !Array.isArray(value))
}

function resolveSelectedKey(pathname: string) {
  if (pathname.startsWith('/orders')) return '/orders'
  if (pathname.startsWith('/profile')) return '/profile'
  return '/hall'
}

function formatWorkerStatus(status: string) {
  if (status === 'active') return '已启用'
  if (status === 'pending_review') return '待处理'
  if (status === 'rejected') return '已冻结'
  if (status === 'disabled') return '已停用'
  return '未登录'
}
