import { useCallback, useEffect, useMemo, useRef, useState, type CSSProperties } from "react";
import { createPortal } from "react-dom";
import { CloseOutlined, LeftOutlined, RightOutlined } from "@ant-design/icons";
import "../styles/components/onboarding.css";

// ─── Types ───────────────────────────────────────────────────

export type TourPhaseId = "chat" | "image" | "video";

interface TooltipStep {
  target: string;
  title: string;
  description: string;
  /** Which side of the target to place the tooltip on (preferred). */
  placement?: "top" | "bottom" | "left" | "right";
  /** If true, this step requires the user to interact with the element to proceed. */
  interactive?: boolean;
  /** Shown as hint text when interactive. */
  actionHint?: string;
}

interface TourPhase {
  id: TourPhaseId;
  label: string;
  steps: TooltipStep[];
}

interface OnboardingTourProps {
  active: boolean;
  phase: TourPhaseId;
  stepIndex: number;
  onNext: (phase: TourPhaseId, stepIndex: number) => void;
  onSkip: (phase: TourPhaseId) => void;
  onDone: () => void;
}

// ─── Tour definitions ────────────────────────────────────────

const PHASES: Record<TourPhaseId, TourPhase> = {
  chat: {
    id: "chat",
    label: "对话模式",
    steps: [
      {
        target: "onboarding-chat-upload",
        title: "参考素材上传",
        description: "点击或拖拽上传图片、视频、音频等参考素材，帮助 AI 更好地理解你的需求。",
        placement: "right",
      },
      {
        target: "onboarding-chat-model",
        title: "AI 模型选择",
        description: "在这里选择对话使用的 AI 模型，不同模型有不同的擅长领域和风格。",
        placement: "bottom",
      },
      {
        target: "onboarding-chat-speed",
        title: "思考速度",
        description: "「思考速度：高」回复更迅速简洁；「思考速度：急速」适合快速问答场景。",
        placement: "bottom",
      },
      {
        target: "onboarding-chat-depth",
        title: "推理深度",
        description: "「推理深度：强」进行更深层逻辑推理；「推理深度：极限」适合复杂多步骤问题。",
        placement: "bottom",
      },
      {
        target: "onboarding-chat-input",
        title: "提示词输入框",
        description: "在这里输入你的问题或创作需求，按 Enter 发送，Shift + Enter 换行。",
        placement: "top",
      },
      {
        target: "onboarding-mode-selector",
        title: "切换到图像生成模式",
        description: "点击「下一步」自动切换，或点击这个按钮手动选择「图像生成」进入下一阶段。",
        placement: "bottom",
      },
    ],
  },
  image: {
    id: "image",
    label: "图像生成",
    steps: [
      {
        target: "onboarding-image-upload",
        title: "参考图上传",
        description: "上传参考图片，AI 将基于参考图的风格和内容生成新图像。支持 PNG / JPG / WebP。",
        placement: "right",
      },
      {
        target: "onboarding-image-model",
        title: "图像模型选择",
        description: "选择用于图像生成的 AI 模型，不同模型在风格、精度和速度上有所侧重。",
        placement: "bottom",
      },
      {
        target: "onboarding-image-settings",
        title: "比例与分辨率",
        description: "设置生成图像的宽高比（如 16:9、1:1）和清晰度（1K/2K），根据使用场景选择。",
        placement: "bottom",
      },
      {
        target: "onboarding-image-grid",
        title: "单图 / 多宫格模式",
        description: "「单图」生成一张完整图像；「多宫格」一次生成多张变体供你挑选最佳方案。",
        placement: "bottom",
      },
      {
        target: "onboarding-image-input",
        title: "图像提示词",
        description: "描述你想要的图像内容、风格和细节，越具体效果越好。",
        placement: "top",
      },
      {
        target: "onboarding-mode-selector",
        title: "切换到视频生成模式",
        description: "点击「下一步」自动切换，或点击这个按钮手动选择「视频生成」进入下一阶段。",
        placement: "bottom",
      },
    ],
  },
  video: {
    id: "video",
    label: "视频生成",
    steps: [
      {
        target: "onboarding-video-upload",
        title: "参考素材上传",
        description: "上传参考图片或视频片段，帮助 AI 确定视频的风格、色调和内容方向。",
        placement: "right",
      },
      {
        target: "onboarding-video-model",
        title: "视频模型选择",
        description: "选择视频生成模型。不同模型在画质、时长、运动流畅度上各有优势。",
        placement: "bottom",
      },
      {
        target: "onboarding-video-frame",
        title: "生成方式：全能 / 首尾帧",
        description: "「全能参考」根据描述直接生成；「首尾帧」通过设定起始和结束画面精确控制转场。",
        placement: "bottom",
      },
      {
        target: "onboarding-video-ratio",
        title: "视频画面比例",
        description: "选择画面比例。9:16 适合手机短视频（抖音/Reels），16:9 适合横屏展示。",
        placement: "bottom",
      },
      {
        target: "onboarding-video-duration",
        title: "视频时长设置",
        description: "设置生成视频的秒数。时长越长，生成时间越久，建议从 5 秒开始尝试。",
        placement: "bottom",
      },
      {
        target: "onboarding-video-quality",
        title: "分辨率与画质",
        description: "选择视频清晰度。720P 生成更快适合预览，1080P 画质更高适合最终成品。",
        placement: "bottom",
      },
      {
        target: "onboarding-video-generate",
        title: "一切就绪，开始创作！",
        description: "设置完毕后，点击发送按钮（或按 Enter）即可开始你的首次视频生成。祝你创作愉快！",
        placement: "top",
      },
    ],
  },
};

// ─── Connector line calculation ──────────────────────────────

interface ConnectorPoints {
  x1: number; y1: number; // tooltip edge center
  x2: number; y2: number; // target edge center
}

function calcConnector(
  tooltipRect: DOMRect,
  targetRect: DOMRect,
  placement: TooltipStep["placement"],
): ConnectorPoints {
  const tx = targetRect.left + targetRect.width / 2;
  const ty = targetRect.top + targetRect.height / 2;
  const tcx = tooltipRect.left + tooltipRect.width / 2;
  const tcy = tooltipRect.top + tooltipRect.height / 2;

  switch (placement) {
    case "top":
      return { x1: tcx, y1: tooltipRect.bottom, x2: tx, y2: targetRect.top };
    case "bottom":
      return { x1: tcx, y1: tooltipRect.top, x2: tx, y2: targetRect.bottom };
    case "left":
      return { x1: tooltipRect.right, y1: tcy, x2: targetRect.left, y2: ty };
    case "right":
      return { x1: tooltipRect.left, y1: tcy, x2: targetRect.right, y2: ty };
    default:
      return { x1: tcx, y1: tooltipRect.top, x2: tx, y2: targetRect.bottom };
  }
}

// ─── Placement engine ─────────────────────────────────────────

interface PlacementResult {
  left: number;
  top: number;
  actualPlacement: TooltipStep["placement"];
}

/** Score a candidate — lower is better. Penalises covering the target or overflow. */
function scorePlacement(
  left: number, top: number, tw: number, th: number,
  targetRect: DOMRect, vw: number, vh: number,
): number {
  let score = 0;
  // Overflow penalty
  if (left < 0) score += Math.abs(left);
  if (top < 0) score += Math.abs(top);
  if (left + tw > vw) score += (left + tw - vw);
  if (top + th > vh) score += (top + th - vh);
  // Overlap with target penalty (avoid covering the highlighted element)
  const overlapX = Math.max(0, Math.min(left + tw, targetRect.right) - Math.max(left, targetRect.left));
  const overlapY = Math.max(0, Math.min(top + th, targetRect.bottom) - Math.max(top, targetRect.top));
  if (overlapX > 0 && overlapY > 0) score += overlapX * overlapY * 0.01;
  return score;
}

function findBestPlacement(
  targetRect: DOMRect, tw: number, th: number,
  preferred: TooltipStep["placement"],
): PlacementResult {
  const gap = 144;
  const vw = window.innerWidth;
  const vh = window.innerHeight;
  const all: Array<TooltipStep["placement"]> = [
    preferred ?? "bottom",
    ...(["bottom", "top", "right", "left"] as const).filter((p) => p !== (preferred ?? "bottom")),
  ];

  let best: PlacementResult = { left: 0, top: 0, actualPlacement: "bottom" };
  let bestScore = Infinity;

  for (const p of all) {
    let left = 0, top = 0;
    switch (p) {
      case "bottom":
        left = targetRect.left + targetRect.width / 2 - tw / 2;
        top = targetRect.bottom + gap;
        break;
      case "top":
        left = targetRect.left + targetRect.width / 2 - tw / 2;
        top = targetRect.top - th - gap;
        break;
      case "right":
        left = targetRect.right + gap;
        top = targetRect.top + targetRect.height / 2 - th / 2;
        break;
      case "left":
        left = targetRect.left - tw - gap;
        top = targetRect.top + targetRect.height / 2 - th / 2;
        break;
    }
    left = Math.max(12, Math.min(left, vw - tw - 12));
    top = Math.max(12, Math.min(top, vh - th - 12));

    const s = scorePlacement(left, top, tw, th, targetRect, vw, vh);
    if (s < bestScore) {
      bestScore = s;
      best = { left, top, actualPlacement: p };
    }
    if (s === 0) break; // perfect
  }
  return best;
}

// ─── Component ────────────────────────────────────────────────

export default function OnboardingTour({
  active, phase, stepIndex, onNext, onSkip, onDone,
}: OnboardingTourProps) {
  const [pos, setPos] = useState<PlacementResult>({ left: 0, top: 0, actualPlacement: "bottom" });
  const [targetRect, setTargetRect] = useState<DOMRect | null>(null);
  const [visible, setVisible] = useState(false);
  const [connector, setConnector] = useState<ConnectorPoints | null>(null);
  const tooltipRef = useRef<HTMLDivElement>(null);
  const prevPhaseRef = useRef(phase);
  const prevStepRef = useRef(stepIndex);

  const phaseDef = PHASES[phase];
  const currentStep = phaseDef?.steps[stepIndex];
  const totalSteps = phaseDef?.steps.length ?? 0;
  const isLastStep = stepIndex >= totalSteps - 1;
  const isVideoLastStep = phase === "video" && isLastStep;

  const stepChanged = prevPhaseRef.current !== phase || prevStepRef.current !== stepIndex;
  prevPhaseRef.current = phase;
  prevStepRef.current = stepIndex;

  const recalc = useCallback(() => {
    if (!currentStep) return;
    const el = document.querySelector(`[data-onboarding="${currentStep.target}"]`) as HTMLElement | null;
    if (!el) return; // Will be retried by the polling loop
    const rect = el.getBoundingClientRect();
    setTargetRect(rect);

    const tooltip = tooltipRef.current;
    if (!tooltip) return;
    const tr = tooltip.getBoundingClientRect();
    const best = findBestPlacement(rect, tr.width, tr.height, currentStep.placement);
    setPos(best);

    // Recalculate tooltip rect after position update (use the same best pos)
    const virtualTooltipRect = new DOMRect(best.left, best.top, tr.width, tr.height);
    setConnector(calcConnector(virtualTooltipRect, rect, best.actualPlacement));
  }, [currentStep]);

  useEffect(() => {
    if (!active) { setVisible(false); return; }
    const t = setTimeout(() => { setVisible(true); recalc(); }, 120);
    return () => clearTimeout(t);
  }, [active, phase, stepIndex, recalc]);

  // Reposition and retry when elements aren't ready
  useEffect(() => {
    if (!active || !visible) return;
    const h = () => recalc();
    window.addEventListener("resize", h);
    window.addEventListener("scroll", h, true);
    const obs = new MutationObserver(h);
    obs.observe(document.body, { childList: true, subtree: true, attributes: true });

    // Polling retry: keep looking for the target element if not found yet
    let retryId: number | null = null;
    let attempts = 0;
    const poll = () => {
      recalc();
      attempts += 1;
      if (attempts < 40) retryId = requestAnimationFrame(poll);
    };
    // Start polling after a short delay
    const startTimer = setTimeout(() => { poll(); }, 200);
    return () => {
      window.removeEventListener("resize", h);
      window.removeEventListener("scroll", h, true);
      obs.disconnect();
      clearTimeout(startTimer);
      if (retryId !== null) cancelAnimationFrame(retryId);
    };
  }, [active, visible, recalc]);

  // Animate in on step change
  useEffect(() => {
    if (!active || !visible || !stepChanged) return;
    const el = tooltipRef.current;
    if (!el) return;
    el.classList.remove("onboarding-tooltip--pop");
    void el.offsetWidth; // force reflow
    el.classList.add("onboarding-tooltip--pop");
  }, [active, visible, stepChanged, phase, stepIndex]);

  if (!active || !currentStep) return null;

  const connectorPath = connector
    ? `M ${connector.x1} ${connector.y1} L ${connector.x2} ${connector.y2}`
    : "";

  const arrowAngle = connector
    ? Math.atan2(connector.y2 - connector.y1, connector.x2 - connector.x1) * (180 / Math.PI)
    : 0;

  const clipPath = targetRect
    ? `polygon(0% 0%, 0% 100%, ${targetRect.left - 6}px 100%, ${targetRect.left - 6}px ${targetRect.top - 6}px, ${targetRect.right + 6}px ${targetRect.top - 6}px, ${targetRect.right + 6}px ${targetRect.bottom + 6}px, ${targetRect.left - 6}px ${targetRect.bottom + 6}px, ${targetRect.left - 6}px 100%, 100% 100%, 100% 0%)`
    : "";

  return createPortal(
    <div className={`onboarding-root${visible ? " is-visible" : ""}`} aria-label="新手引导教程">
      {/* Overlay */}
      <div className="onboarding-overlay" style={{ clipPath, WebkitClipPath: clipPath }} />

      {/* Spotlight ring */}
      {targetRect && (
        <div
          className="onboarding-spotlight"
          style={{
            left: targetRect.left - 8,
            top: targetRect.top - 8,
            width: targetRect.width + 16,
            height: targetRect.height + 16,
          }}
        >
          {/* Animated pulse ring */}
          <div className="onboarding-spotlight__pulse" />
          <div className="onboarding-spotlight__pulse onboarding-spotlight__pulse--delay" />
        </div>
      )}

      {/* Connector SVG line */}
      {connector && (
        <svg className="onboarding-connector" aria-hidden="true">
          <defs>
            <linearGradient id="ob-conn-grad" x1="0%" y1="0%" x2="100%" y2="0%">
              <stop offset="0%" stopColor="var(--accent, #00ff88)" stopOpacity="0.2" />
              <stop offset="100%" stopColor="var(--accent, #00ff88)" stopOpacity="0.9" />
            </linearGradient>
          </defs>
          {/* Animated dash line */}
          <path
            d={connectorPath}
            fill="none"
            stroke="var(--accent, #00ff88)"
            strokeWidth="2"
            strokeDasharray="8 4"
            strokeLinecap="round"
            opacity="0.7"
            className="onboarding-connector__path"
          />
          {/* Arrow at target end */}
          <circle
            cx={connector.x2}
            cy={connector.y2}
            r="5"
            fill="var(--accent, #00ff88)"
            className="onboarding-connector__dot"
          />
        </svg>
      )}

      {/* Tooltip card */}
      <div
        ref={tooltipRef}
        className={`onboarding-tooltip onboarding-tooltip--${pos.actualPlacement}`}
        style={{ left: pos.left, top: pos.top }}
        role="dialog"
        aria-label={currentStep.title}
      >
        {/* Arrow pointing toward target */}
        <div
          className={`onboarding-tooltip__arrow onboarding-tooltip__arrow--${pos.actualPlacement}`}
          style={{ transform: `rotate(${arrowAngle}deg)` }}
        />

        <div className="onboarding-tooltip__head">
          <span className="onboarding-tooltip__phase-badge">{phaseDef.label}</span>
          <span className="onboarding-tooltip__counter">
            {stepIndex + 1} / {totalSteps}
          </span>
        </div>

        <strong className="onboarding-tooltip__title">{currentStep.title}</strong>
        <p className="onboarding-tooltip__desc">{currentStep.description}</p>

        <div className="onboarding-tooltip__actions">
          <button type="button" className="onboarding-tooltip__btn onboarding-tooltip__btn--ghost" onClick={onDone}>
            <CloseOutlined /> 跳过教程
          </button>
          {stepIndex > 0 && (
            <button
              type="button"
              className="onboarding-tooltip__btn onboarding-tooltip__btn--ghost"
              onClick={() => onNext(phase, stepIndex - 1)}
            >
              <LeftOutlined /> 上一步
            </button>
          )}
          {isVideoLastStep ? (
            <button type="button" className="onboarding-tooltip__btn onboarding-tooltip__btn--primary" onClick={onDone}>
              开始使用 <RightOutlined />
            </button>
          ) : isLastStep && phase !== "video" ? (
            <button type="button" className="onboarding-tooltip__btn onboarding-tooltip__btn--primary" onClick={() => onSkip(phase)}>
              {phase === "chat" ? "进入图像生成" : "进入视频生成"} <RightOutlined />
            </button>
          ) : (
            <button type="button" className="onboarding-tooltip__btn onboarding-tooltip__btn--primary" onClick={() => onNext(phase, stepIndex + 1)}>
              下一步 <RightOutlined />
            </button>
          )}
        </div>
      </div>

      {/* Bottom progress bar */}
      <div className="onboarding-progress" aria-hidden="true">
        {(["chat", "image", "video"] as TourPhaseId[]).map((p) => (
          <div key={p} className="onboarding-progress__phase">
            <div
              className={`onboarding-progress__dot${p === phase ? " is-active" : ""}${
                (["chat", "image", "video"].indexOf(p) < ["chat", "image", "video"].indexOf(phase)) ? " is-done" : ""
              }`}
            />
            <span>{PHASES[p].label}</span>
          </div>
        ))}
      </div>
    </div>,
    document.body,
  );
}
