"use client"

import { useCallback, useMemo, useState } from "react"
import Link from "next/link"
import { Mail, MailOpen, Plus, Send, Inbox, Search, Loader2, ChevronLeft, ChevronRight, Star, RotateCcw, Users } from "lucide-react"
import { useTranslations } from "next-intl"
import { toast } from "sonner"

import { Badge } from "@/shared/components/ui/badge"
import { Button } from "@/shared/components/ui/button"
import { Card, CardContent, CardHeader } from "@/shared/components/ui/card"
import { EmptyState } from "@/shared/components/ui/empty-state"
import { Input } from "@/shared/components/ui/input"
import { Tabs, TabsList, TabsTrigger } from "@/shared/components/ui/tabs"
import { cn, formatDate } from "@/shared/lib/utils"
import { usePermission } from "@/shared/hooks/use-permission"
import { Permissions } from "@/shared/types/permissions"

import { useMessageSearch } from "../hooks/use-message-search"
import { useMessageListService } from "../services/message-list-service-context"
import type { Message, MessageType } from "../types"

// P1-2: 新增 "starred" Tab 类型
type Tab = "inbox" | "sent" | "starred"

const isTab = (v: string): v is Tab => v === "inbox" || v === "sent" || v === "starred"

/** 客户端分页大小 */
const PAGE_SIZE = 20

export function MessageList({
  messages,
  currentUserId,
  initialType = "inbox",
  canGroupSend = false,
}: {
  messages: Message[]
  currentUserId: string
  initialType?: MessageType
  canGroupSend?: boolean
}) {
  const t = useTranslations("messages")
  const [tab, setTab] = useState<Tab>(initialType === "sent" ? "sent" : "inbox")
  const [currentPage, setCurrentPage] = useState(1)
  const [starredOverride, setStarredOverride] = useState<Record<string, boolean>>({})
  const [togglingStarId, setTogglingStarId] = useState<string | null>(null)
  const [starredMessages, setStarredMessages] = useState<Message[] | null>(null)
  const [loadingStarred, setLoadingStarred] = useState(false)
  // P2-4: 撤回状态覆盖（按消息 ID 维度，撤回成功后立即隐藏原内容）
  const [recalledOverride, setRecalledOverride] = useState<Record<string, boolean>>({})
  const [recallingId, setRecallingId] = useState<string | null>(null)
  const { hasPermission } = usePermission()
  const canSend = hasPermission(Permissions.MESSAGE_SEND)
  // P1-8: 通过依赖注入获取消息列表服务，而非直接 import actions
  const messageService = useMessageListService()

  const { keyword, setKeyword, results, searching, isUsingInitial } = useMessageSearch({
    searchAction: messageService.search,
    tab: tab === "starred" ? "inbox" : tab,
  })

  // P1-2: 切换到 starred Tab 时单独加载星标消息（type=all + starredOnly=true）
  // 由于 useMessageSearch 仅支持 inbox/sent 搜索，starred Tab 使用独立加载逻辑
  const loadStarred = useCallback(async () => {
    setLoadingStarred(true)
    try {
      const res = await messageService.search({ type: "all", starredOnly: true })
      setStarredMessages(res.success && res.data ? res.data.items : [])
    } catch {
      setStarredMessages([])
    } finally {
      setLoadingStarred(false)
    }
  }, [messageService])

  // 客户端过滤仅在初始数据（type=all）时需要，搜索结果已由服务端按 tab 过滤
  // P1-2: starred Tab 使用 starredMessages 状态
  const filtered = useMemo(() => {
    if (tab === "starred") {
      // starred Tab：若有搜索关键字则用搜索结果，否则用 starredMessages
      if (keyword.trim().length > 0 && results) {
        return results.filter((m) => m.receiverId === currentUserId)
      }
      return starredMessages ?? []
    }
    const displayMessages = isUsingInitial ? messages : (results ?? [])
    if (!isUsingInitial) return displayMessages
    if (tab === "inbox") return displayMessages.filter((m) => m.receiverId === currentUserId)
    return displayMessages.filter((m) => m.senderId === currentUserId)
  }, [messages, results, tab, currentUserId, isUsingInitial, starredMessages, keyword])

  // 客户端分页：超过 PAGE_SIZE 条时显示分页 UI
  const totalPages = Math.max(1, Math.ceil(filtered.length / PAGE_SIZE))
  const safePage = Math.min(currentPage, totalPages)
  const paged = filtered.slice((safePage - 1) * PAGE_SIZE, safePage * PAGE_SIZE)
  const showPagination = filtered.length > PAGE_SIZE

  // 切换 tab 或搜索时重置分页
  const handleTabChange = (v: string): void => {
    if (!isTab(v)) return
    setTab(v)
    setCurrentPage(1)
    // P1-2: 切换到 starred 时触发加载
    if (v === "starred") {
      void loadStarred()
    }
  }

  const handleKeywordChange = (v: string): void => {
    setKeyword(v)
    setCurrentPage(1)
  }

  const getIsStarred = (m: Message): boolean => {
    const override = starredOverride[m.id]
    return override === undefined ? m.isStarred : override
  }

  const handleToggleStar = useCallback(
    async (e: React.MouseEvent, messageId: string, currentStarred: boolean): Promise<void> => {
      e.preventDefault()
      e.stopPropagation()
      setTogglingStarId(messageId)
      // 乐观更新
      setStarredOverride((prev) => ({ ...prev, [messageId]: !currentStarred }))
      try {
        const res = await messageService.toggleStar(messageId)
        if (res.success) {
          toast.success(t("messages.starToggled"))
          // P1-2: 当前在 starred Tab 时重新加载星标列表
          if (tab === "starred") {
            void loadStarred()
          }
        } else {
          // 回滚
          setStarredOverride((prev) => ({ ...prev, [messageId]: currentStarred }))
          toast.error(res.message)
        }
      } catch {
        // 回滚
        setStarredOverride((prev) => ({ ...prev, [messageId]: currentStarred }))
        toast.error(t("messages.sendFailed"))
      } finally {
        setTogglingStarId(null)
      }
    },
    [t, tab, loadStarred, messageService]
  )

  // P2-4: 撤回消息（仅发送方，2 分钟窗口内）
  const handleRecall = useCallback(
    async (e: React.MouseEvent, message: Message): Promise<void> => {
      e.preventDefault()
      e.stopPropagation()
      setRecallingId(message.id)
      try {
        const res = await messageService.recall(message.id)
        if (res.success) {
          // 同步 UI：立即显示"已撤回"占位
          setRecalledOverride((prev) => ({ ...prev, [message.id]: true }))
          toast.success(t("messages.recalled"))
        } else {
          if (res.message === "Recall window expired") {
            toast.error(t("messages.recallExpired"))
          } else {
            toast.error(res.message || t("messages.recallFailed"))
          }
        }
      } catch {
        toast.error(t("messages.recallFailed"))
      } finally {
        setRecallingId(null)
      }
    },
    [t, messageService]
  )

  const getIsRecalled = (m: Message): boolean => {
    const override = recalledOverride[m.id]
    return override === undefined ? m.recalledAt !== null : override
  }

  // P1-4: 空状态文案按 Tab 区分
  const getEmptyState = () => {
    if (tab === "starred") {
      return {
        title: t("empty.noStarred"),
        description: t("empty.inboxEmptyDesc"),
      }
    }
    return tab === "inbox"
      ? { title: t("empty.inboxEmpty"), description: t("empty.inboxEmptyDesc") }
      : { title: t("empty.sentEmpty"), description: t("empty.sentEmptyDesc") }
  }

  return (
    <div className="space-y-6">
      <div className="flex flex-wrap items-center justify-between gap-3">
        <Tabs value={tab} onValueChange={handleTabChange}>
          <TabsList>
            <TabsTrigger value="inbox" className="gap-2">
              <Inbox className="h-4 w-4" />
              {t("tabs.inbox")}
            </TabsTrigger>
            <TabsTrigger value="sent" className="gap-2">
              <Send className="h-4 w-4" />
              {t("tabs.sent")}
            </TabsTrigger>
            {/* P1-2: 新增星标 Tab */}
            <TabsTrigger value="starred" className="gap-2">
              <Star className="h-4 w-4" />
              {t("actions.star")}
            </TabsTrigger>
          </TabsList>
        </Tabs>
        {canSend ? (
          <div className="flex gap-2">
            <Button asChild>
              <Link href="/messages/compose">
                <Plus className="mr-2 h-4 w-4" />
                {t("actions.compose")}
              </Link>
            </Button>
            {canGroupSend ? (
              <Button asChild variant="outline">
                <Link href="/messages/group-compose">
                  <Users className="mr-2 h-4 w-4" />
                  {t("title.groupCompose")}
                </Link>
              </Button>
            ) : null}
          </div>
        ) : null}
      </div>

      {/* 搜索框 */}
      <div className="relative">
        <Search className="text-muted-foreground absolute left-3 top-1/2 size-4 -translate-y-1/2" aria-hidden="true" />
        <Input
          type="search"
          aria-label={t("search.placeholder")}
          aria-busy={searching || loadingStarred}
          placeholder={t("search.placeholder")}
          value={keyword}
          onChange={(e) => handleKeywordChange(e.target.value)}
          className="pl-9"
        />
        {searching || loadingStarred ? (
          <Loader2 className="text-muted-foreground absolute right-3 top-1/2 size-4 -translate-y-1/2 animate-spin" aria-hidden="true" />
        ) : null}
      </div>

      {paged.length === 0 ? (
        <EmptyState
          title={getEmptyState().title}
          description={getEmptyState().description}
          icon={Mail}
          className="h-auto border-none shadow-none"
        />
      ) : (
        <>
          <div className="space-y-3">
            {paged.map((m) => {
              const isReceived = m.receiverId === currentUserId
              const counterpart = isReceived ? m.senderName : m.receiverName
              const unread = isReceived && !m.isRead
              const isStarred = getIsStarred(m)
              // P2-4: 撤回状态
              const isRecalled = getIsRecalled(m)
              const canRecallItem =
                !isReceived &&
                canSend &&
                !isRecalled &&
                Date.now() - new Date(m.createdAt).getTime() <= 2 * 60 * 1000
              return (
                <Link key={m.id} href={`/messages/${m.id}`} className="block" aria-label={m.subject ?? t("meta.noSubject")}>
                  <Card className={cn("transition-colors hover:bg-accent/50", unread && "border-primary/40")}>
                    <CardHeader className="flex flex-row items-start justify-between gap-2 space-y-0 pb-3">
                      <div className="space-y-1">
                        <div className="flex items-center gap-2">
                          {isRecalled ? (
                            <RotateCcw className="text-muted-foreground h-4 w-4" aria-hidden="true" />
                          ) : unread ? (
                            <Mail className="h-4 w-4 text-primary" aria-hidden="true" />
                          ) : (
                            <MailOpen className="text-muted-foreground h-4 w-4" aria-hidden="true" />
                          )}
                          <span className={cn("text-sm font-medium", unread && !isRecalled && "text-primary")}>
                            {m.subject ?? t("meta.noSubject")}
                          </span>
                          {/* P2-4: 已撤回优先显示徽章 */}
                          {isRecalled ? (
                            <Badge variant="secondary" className="text-xs">{t("status.recalled")}</Badge>
                          ) : null}
                          {unread && !isRecalled ? (
                            <Badge variant="default" className="text-xs">{t("status.new")}</Badge>
                          ) : null}
                          {isStarred ? (
                            <Star className="h-3.5 w-3.5 fill-yellow-400 text-yellow-400" aria-hidden="true" />
                          ) : null}
                        </div>
                        <p className="text-muted-foreground text-xs">
                          {isReceived ? t("meta.from") : t("meta.to")}: {counterpart ?? t("meta.unknown")}
                        </p>
                      </div>
                      <div className="flex shrink-0 items-center gap-1">
                        {/* P2-4: 撤回按钮（仅发送方在 2 分钟窗口内可见） */}
                        {canRecallItem ? (
                          <button
                            type="button"
                            onClick={(e) => void handleRecall(e, m)}
                            disabled={recallingId === m.id}
                            aria-label={t("actions.recall")}
                            className="text-muted-foreground hover:text-foreground inline-flex size-7 items-center justify-center rounded-md transition-colors hover:bg-accent disabled:opacity-50"
                          >
                            <RotateCcw className="h-4 w-4" />
                          </button>
                        ) : null}
                        <button
                          type="button"
                          onClick={(e) => void handleToggleStar(e, m.id, isStarred)}
                          disabled={togglingStarId === m.id}
                          aria-label={isStarred ? t("actions.unstar") : t("actions.star")}
                          aria-pressed={isStarred}
                          className="text-muted-foreground hover:text-foreground inline-flex size-7 items-center justify-center rounded-md transition-colors hover:bg-accent disabled:opacity-50"
                        >
                          <Star
                            className={cn(
                              "h-4 w-4 transition-colors",
                              isStarred && "fill-yellow-400 text-yellow-400"
                            )}
                          />
                        </button>
                        <span className="text-muted-foreground text-xs">
                          {formatDate(m.createdAt)}
                        </span>
                      </div>
                    </CardHeader>
                    <CardContent className="pt-0">
                      {/* P2-4: 已撤回消息显示占位文案，隐藏原始内容 */}
                      {isRecalled ? (
                        <p className="text-muted-foreground italic text-sm">{t("status.recalled")}</p>
                      ) : (
                        <p className="text-muted-foreground line-clamp-2 text-sm whitespace-pre-wrap">
                          {m.content}
                        </p>
                      )}
                    </CardContent>
                  </Card>
                </Link>
              )
            })}
          </div>

          {showPagination ? (
            <div className="flex items-center justify-center gap-4 pt-2" role="navigation" aria-label={t("pagination.nav")}>
              <Button
                variant="outline"
                size="sm"
                onClick={() => setCurrentPage((p) => Math.max(1, p - 1))}
                disabled={safePage <= 1}
                aria-label={t("pagination.previous")}
              >
                <ChevronLeft className="h-4 w-4" />
              </Button>
              <span className="text-muted-foreground text-sm" aria-live="polite">
                {t("pagination.page", { current: safePage, total: totalPages })}
              </span>
              <Button
                variant="outline"
                size="sm"
                onClick={() => setCurrentPage((p) => Math.min(totalPages, p + 1))}
                disabled={safePage >= totalPages}
                aria-label={t("pagination.next")}
              >
                <ChevronRight className="h-4 w-4" />
              </Button>
            </div>
          ) : null}
        </>
      )}
    </div>
  )
}
