import { useCallback, useEffect, useMemo, useRef, useState } from "react"
import { createPortal } from "react-dom"
import type { TaskPanelArtifact, TaskPanelItem, TaskPanelStatus } from "@qjclaw/shared-types"
import { renderExpertIcon } from "../../components/icons/AppIcons"
import { Panel } from "../../components/ui/Panel"
import { ScrollArea } from "../../components/ui/ScrollArea"
import type { ExpertVisualKey } from "../shell/ExpertTree"
import { getDefaultTaskPanelDate, loadTaskPanelItems } from "./taskPanelData"

const statusLabels: Record<TaskPanelStatus, string> = {
  pending: "待处理",
  running: "执行中",
  completed: "已完成",
  failed: "失败"
}

function resolveTaskExpertIconKey(expertName: string): ExpertVisualKey {
  const seed = expertName.toLowerCase()
  if (/xiaohongshu|xhs|rednote|小红书/.test(seed)) {
    return "xiaohongshu"
  }
  if (/douyin|抖音/.test(seed)) {
    return "douyin"
  }
  if (/tiktok/.test(seed)) {
    return "tiktok"
  }
  if (/wechat|weixin|公众号|微信/.test(seed)) {
    return "wechat"
  }
  if (/zhihu|知乎/.test(seed)) {
    return "zhihu"
  }
  if (/content-account|planner|账号规划|内容账号规划/.test(seed)) {
    return "planner"
  }
  if (/precision-leads|线索|lead/.test(seed)) {
    return "leads"
  }
  if (/sales-champion|销售冠军|销冠|sales champion/.test(seed)) {
    return "sales"
  }
  if (/poster|海报/.test(seed)) {
    return "poster"
  }
  if (/(^|[\s-])x($|[\s-])|twitter/.test(seed)) {
    return "x"
  }
  if (/geo/.test(seed)) {
    return "geo"
  }
  if (/browser|automation|chrome|playwright|web|浏览器|自动化/.test(seed)) {
    return "browser"
  }
  return "general"
}

function TaskStatus({ item }: { item: TaskPanelItem }) {
  return (
    <div className={"task-panel-status task-panel-status-" + item.status}>
      <span className="task-panel-status-icon" title={item.statusDetail} aria-hidden="true">
        {item.status === "completed" ? <span>✓</span> : null}
        {item.status === "running" ? (
          <span className="task-panel-running-dots" aria-hidden="true">
            <span />
            <span />
            <span />
          </span>
        ) : null}
        {item.status === "pending" ? <span>•</span> : null}
        {item.status === "failed" ? <span>!</span> : null}
      </span>
      <strong className="task-panel-status-text" title={item.statusDetail}>{statusLabels[item.status]}</strong>
    </div>
  )
}

function TaskArtifactList({
  artifacts,
  copiedArtifactId,
  onCopy
}: {
  artifacts: TaskPanelArtifact[]
  copiedArtifactId: string
  onCopy: (artifactId: string, artifactUrl: string) => void
}) {
  return (
    <ul className="task-panel-artifact-list" aria-label="产物清单">
      {artifacts.map((artifact) => (
        <li
          key={artifact.id}
          className={copiedArtifactId === artifact.id ? "task-panel-artifact-item-copied" : undefined}
          title={artifact.url ?? artifact.name}
        >
          <span className="task-panel-artifact-name" title={artifact.name}>{artifact.name}</span>
          {artifact.url ? (
            <button
              type="button"
              className="task-panel-artifact-url"
              title={artifact.url}
              onClick={() => onCopy(artifact.id, artifact.url ?? "")}
            >
              {artifact.url}
            </button>
          ) : null}
          {copiedArtifactId === artifact.id ? (
            <span className="task-panel-artifact-copied" aria-live="polite">已复制</span>
          ) : null}
        </li>
      ))}
    </ul>
  )
}

function TaskArtifacts({ item }: { item: TaskPanelItem }) {
  const [copiedArtifactId, setCopiedArtifactId] = useState("")
  const [isMenuOpen, setIsMenuOpen] = useState(false)
  const [popoverPosition, setPopoverPosition] = useState<{ top: number; left: number; width: number; maxHeight: number } | null>(null)
  const menuRef = useRef<HTMLDivElement | null>(null)
  const triggerRef = useRef<HTMLButtonElement | null>(null)
  const popoverRef = useRef<HTMLDivElement | null>(null)
  const copiedTimerRef = useRef<number | null>(null)

  useEffect(() => {
    return () => {
      if (copiedTimerRef.current !== null) {
        window.clearTimeout(copiedTimerRef.current)
      }
    }
  }, [])

  const updatePopoverPosition = useCallback(() => {
    const triggerElement = triggerRef.current
    if (!triggerElement) {
      return
    }

    const margin = 16
    const gap = 8
    const triggerRect = triggerElement.getBoundingClientRect()
    const width = Math.min(520, Math.max(280, window.innerWidth - margin * 2))
    const left = Math.min(Math.max(triggerRect.left, margin), window.innerWidth - width - margin)
    const belowTop = triggerRect.bottom + gap
    const spaceBelow = window.innerHeight - belowTop - margin
    const spaceAbove = triggerRect.top - margin - gap
    const preferBelow = spaceBelow >= 160 || spaceBelow >= spaceAbove
    const maxHeight = Math.min(220, Math.max(140, preferBelow ? spaceBelow : spaceAbove))
    const top = preferBelow ? belowTop : Math.max(margin, triggerRect.top - gap - maxHeight)

    setPopoverPosition({ top, left, width, maxHeight })
  }, [])

  useEffect(() => {
    setIsMenuOpen(false)
    setCopiedArtifactId("")
  }, [item.id])

  useEffect(() => {
    if (!isMenuOpen) {
      return
    }

    const handlePointerDown = (event: PointerEvent) => {
      const menuElement = menuRef.current
      const popoverElement = popoverRef.current
      if (
        event.target instanceof Node
        && !menuElement?.contains(event.target)
        && !popoverElement?.contains(event.target)
      ) {
        setIsMenuOpen(false)
      }
    }

    const handleKeyDown = (event: KeyboardEvent) => {
      if (event.key === "Escape") {
        setIsMenuOpen(false)
      }
    }

    document.addEventListener("pointerdown", handlePointerDown, true)
    document.addEventListener("keydown", handleKeyDown)

    return () => {
      document.removeEventListener("pointerdown", handlePointerDown, true)
      document.removeEventListener("keydown", handleKeyDown)
    }
  }, [isMenuOpen])

  useEffect(() => {
    if (!isMenuOpen) {
      return
    }

    updatePopoverPosition()
    window.addEventListener("resize", updatePopoverPosition)
    window.addEventListener("scroll", updatePopoverPosition, true)

    return () => {
      window.removeEventListener("resize", updatePopoverPosition)
      window.removeEventListener("scroll", updatePopoverPosition, true)
    }
  }, [isMenuOpen, updatePopoverPosition])

  const copyArtifactUrl = async (artifactId: string, artifactUrl: string) => {
    try {
      await navigator.clipboard.writeText(artifactUrl)
      setCopiedArtifactId(artifactId)
      if (copiedTimerRef.current !== null) {
        window.clearTimeout(copiedTimerRef.current)
      }
      copiedTimerRef.current = window.setTimeout(() => {
        setCopiedArtifactId("")
        copiedTimerRef.current = null
      }, 1400)
    } catch {
      // Copy feedback is best-effort and should not affect task data.
    }
  }

  if (!item.artifacts.length) {
    return (
      <div className="task-panel-artifact-center">
        <span className="task-panel-muted">暂无产物</span>
      </div>
    )
  }

  if (item.artifacts.length <= 2) {
    return (
      <div className="task-panel-artifact-center">
        <TaskArtifactList
          artifacts={item.artifacts}
          copiedArtifactId={copiedArtifactId}
          onCopy={(artifactId, artifactUrl) => void copyArtifactUrl(artifactId, artifactUrl)}
        />
      </div>
    )
  }

  return (
    <div className="task-panel-artifact-menu" ref={menuRef}>
      <button
        ref={triggerRef}
        type="button"
        className="task-panel-artifact-trigger"
        aria-haspopup="menu"
        aria-expanded={isMenuOpen}
        aria-controls={item.id + "-artifact-menu"}
        onClick={() => {
          if (!isMenuOpen) {
            updatePopoverPosition()
          }
          setIsMenuOpen((current) => !current)
        }}
      >
        {item.artifacts.length} 个产物
      </button>
      {isMenuOpen && popoverPosition ? createPortal((
        <div
          ref={popoverRef}
          className="task-panel-artifact-popover"
          id={item.id + "-artifact-menu"}
          role="menu"
          style={{
            top: popoverPosition.top,
            left: popoverPosition.left,
            width: popoverPosition.width,
            maxHeight: popoverPosition.maxHeight
          }}
        >
          <TaskArtifactList
            artifacts={item.artifacts}
            copiedArtifactId={copiedArtifactId}
            onCopy={(artifactId, artifactUrl) => void copyArtifactUrl(artifactId, artifactUrl)}
          />
        </div>
      ), document.body) : null}
    </div>
  )
}

function TaskPanelLoadingState() {
  return (
    <div className="task-panel-loading-state" role="status" aria-label="任务列表加载中">
      {Array.from({ length: 4 }, (_, index) => (
        <div className="task-panel-loading-row" key={index} aria-hidden="true">
          <span className="task-panel-loading-avatar" />
          <span className="task-panel-loading-line task-panel-loading-line-name" />
          <span className="task-panel-loading-line task-panel-loading-line-task" />
          <span className="task-panel-loading-pill" />
          <span className="task-panel-loading-line task-panel-loading-line-artifact" />
        </div>
      ))}
    </div>
  )
}

export function TaskPanelView() {
  const [selectedDate, setSelectedDate] = useState(getDefaultTaskPanelDate)
  const [items, setItems] = useState<TaskPanelItem[]>([])
  const [selectedTaskIds, setSelectedTaskIds] = useState<Record<string, string>>({})
  const [loading, setLoading] = useState(true)
  const [errorText, setErrorText] = useState("")
  const [greetingText, setGreetingText] = useState("")
  const dateInputRef = useRef<HTMLInputElement | null>(null)

  useEffect(() => {
    const greeting = "Hi，今日任务请查收～"
    let index = 0
    setGreetingText("")

    const timer = window.setInterval(() => {
      index += 1
      setGreetingText(greeting.slice(0, index))
      if (index >= greeting.length) {
        window.clearInterval(timer)
      }
    }, 42)

    return () => {
      window.clearInterval(timer)
    }
  }, [])

  useEffect(() => {
    let active = true
    setLoading(true)
    setErrorText("")

    void loadTaskPanelItems(selectedDate)
      .then((nextItems) => {
        if (active) {
          setItems(nextItems)
        }
      })
      .catch((error: unknown) => {
        if (active) {
          setItems([])
          setErrorText(error instanceof Error ? error.message : "任务列表加载失败")
        }
      })
      .finally(() => {
        if (active) {
          setLoading(false)
        }
      })

    return () => {
      active = false
    }
  }, [selectedDate])

  const displayDate = useMemo(() => selectedDate.replaceAll("-", "/"), [selectedDate])
  const displayMonth = useMemo(() => `${Number(selectedDate.slice(5, 7))}月`, [selectedDate])
  const expertRows = useMemo(() => {
    const groups = new Map<string, TaskPanelItem[]>()
    for (const item of items) {
      const groupItems = groups.get(item.expertName)
      if (groupItems) {
        groupItems.push(item)
      } else {
        groups.set(item.expertName, [item])
      }
    }

    return Array.from(groups, ([expertName, tasks]) => {
      const selectedTask = tasks.find((task) => task.id === selectedTaskIds[expertName]) ?? tasks[0]
      return { expertName, tasks, selectedTask }
    })
  }, [items, selectedTaskIds])

  return (
    <div className="page-stack task-panel-page-stack">
      <Panel className="task-panel-page" bodyClassName="task-panel-body">
        <div className="task-panel-header">
          <div className="task-panel-title-group">
            <h1 className="task-panel-heading">任务面板</h1>
            <p className="task-panel-greeting" aria-label="任务面板问候语">{greetingText}</p>
          </div>
          <div className="task-panel-date-field">
            <button
              type="button"
              className="task-panel-date-pill"
              aria-label={"选择日期，当前为 " + displayDate}
              onClick={() => {
                const dateInput = dateInputRef.current
                if (!dateInput) {
                  return
                }
                if (typeof dateInput.showPicker === "function") {
                  dateInput.showPicker()
                } else {
                  dateInput.click()
                }
              }}
            >
              <span className="task-panel-date-calendar" aria-hidden="true">
                <span className="task-panel-date-calendar-month">{displayMonth}</span>
                <span className="task-panel-date-calendar-day">{selectedDate.slice(-2)}</span>
              </span>
              <span className="task-panel-date-value">{displayDate}</span>
            </button>
            <input
              ref={dateInputRef}
              type="date"
              aria-hidden="true"
              tabIndex={-1}
              value={selectedDate}
              onChange={(event) => setSelectedDate(event.currentTarget.value)}
            />
          </div>
        </div>

        <ScrollArea className="scroll-panel task-panel-scroll" aria-busy={loading}>
          {loading ? <TaskPanelLoadingState /> : null}
          {!loading && errorText ? <div className="notice error task-panel-state" role="alert">{errorText}</div> : null}
          {!loading && !errorText && !items.length ? <div className="empty-state task-panel-state">当天暂无任务</div> : null}
          {!loading && !errorText && items.length ? (
            <div className="task-panel-table" role="table" aria-label="任务面板">
              <div className="task-panel-row task-panel-row-head" role="row">
                <div role="columnheader">数字员工</div>
                <div role="columnheader">任务列表</div>
                <div role="columnheader">执行状态</div>
                <div role="columnheader">产物清单</div>
              </div>
              {expertRows.map((row) => (
                <article key={row.expertName} className="task-panel-row" role="row">
                  <div className="task-panel-expert-cell" role="cell">
                    <span className={"task-panel-expert-icon task-panel-expert-icon-" + resolveTaskExpertIconKey(row.expertName)} aria-hidden="true">
                      {renderExpertIcon(resolveTaskExpertIconKey(row.expertName))}
                    </span>
                    <strong title={row.expertName}>{row.expertName}</strong>
                  </div>
                  <div className="task-panel-task-cell" role="cell">
                    <select
                      aria-label={row.expertName + "任务列表"}
                      title={row.selectedTask.taskTitle}
                      value={row.selectedTask.id}
                      onChange={(event) => {
                        const selectedTaskId = event.currentTarget.value
                        setSelectedTaskIds((current) => ({
                          ...current,
                          [row.expertName]: selectedTaskId
                        }))
                      }}
                    >
                      {row.tasks.map((task) => (
                        <option key={task.id} title={task.taskTitle} value={task.id}>{task.taskTitle}</option>
                      ))}
                    </select>
                  </div>
                  <div role="cell">
                    <TaskStatus item={row.selectedTask} />
                  </div>
                  <div role="cell">
                    <TaskArtifacts item={row.selectedTask} />
                  </div>
                </article>
              ))}
            </div>
          ) : null}
        </ScrollArea>
      </Panel>
    </div>
  )
}
