"use client";

import { Download, Share2 } from "lucide-react";
import { useEffect, useRef, useState, type ReactNode } from "react";
import { toast } from "sonner";

import { Button } from "@/components/ui/button";
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog";
import { buildInviteLink, type LinkTarget } from "@/lib/invite/inviteLink";
import { cn } from "@/lib/utils";

import { composePosterPng } from "./compose-poster";
import { PosterCanvas, type PosterConfig } from "./PosterCanvas";
import { POSTER_H, POSTER_TEMPLATES, POSTER_W, PREVIEW_SCALE_MAX, THUMB_SCALE } from "./templates";

const StepLabel = ({ n, children }: { n: number; children: ReactNode }) => (
  <div className="mb-2 flex items-center gap-2 text-meta font-medium text-foreground">
    <span className="inline-flex size-5 items-center justify-center rounded-full bg-primary text-[11px] font-bold text-primary-foreground">
      {n}
    </span>
    {children}
  </div>
);

const ScaledPoster = ({
  config,
  link,
  inviteCode,
  scale,
  testId,
}: {
  config: PosterConfig;
  link: string;
  inviteCode: string;
  scale: number;
  testId?: string;
}) => {
  const w = POSTER_W * scale;
  const h = POSTER_H * scale;
  return (
    <div
      className="relative shrink-0 overflow-hidden rounded-2xl bg-black/5 shadow-sm ring-1 ring-border"
      style={{ width: w, height: h }}
      data-testid={testId}
    >
      <div
        style={{
          position: "absolute",
          top: 0,
          left: 0,
          width: POSTER_W,
          height: POSTER_H,
          transform: `scale(${scale})`,
          transformOrigin: "0 0",
        }}
      >
        <PosterCanvas config={config} link={link} inviteCode={inviteCode} />
      </div>
    </div>
  );
};

export const PosterDialog = ({
  inviteCode,
  target,
  open,
  onOpenChange,
}: {
  inviteCode: string;
  target: LinkTarget;
  open: boolean;
  onOpenChange: (open: boolean) => void;
}) => {
  const previewSlotRef = useRef<HTMLDivElement>(null);
  const [previewScale, setPreviewScale] = useState(PREVIEW_SCALE_MAX);
  const [config, setConfig] = useState<PosterConfig>({
    template: POSTER_TEMPLATES[0],
  });
  const link = buildInviteLink(inviteCode, target);

  // 窄屏：按预览槽可用宽度下调缩放，避免横向溢出
  useEffect(() => {
    if (!open) return;
    const el = previewSlotRef.current;
    if (!el) return;
    const ro = new ResizeObserver(([entry]) => {
      const avail = entry.contentRect.width;
      if (avail <= 0) return;
      setPreviewScale(Math.min(PREVIEW_SCALE_MAX, avail / POSTER_W));
    });
    ro.observe(el);
    return () => ro.disconnect();
  }, [open]);

  const exportPng = async (): Promise<Blob | null> => {
    try {
      return await composePosterPng({ imageUrl: config.template.image, link });
    } catch {
      toast.error("生成失败，请重试");
      return null;
    }
  };

  const download = async () => {
    const blob = await exportPng();
    if (!blob) return;
    const url = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = url;
    a.download = `邀请海报-${config.template.id}-${inviteCode}.png`;
    a.click();
    // iOS 会异步读 blob，立刻 revoke 会下到空文件
    window.setTimeout(() => URL.revokeObjectURL(url), 2000);
    toast.success("海报已保存");
  };

  const share = async () => {
    const blob = await exportPng();
    if (!blob) return;
    const file = new File([blob], `邀请海报-${inviteCode}.png`, { type: "image/png" });
    try {
      await navigator.share({ files: [file] });
    } catch {
      // 用户取消不算失败
    }
  };

  const canShareFile =
    typeof navigator !== "undefined" && !!navigator.canShare?.({ files: [new File([], "x.png", { type: "image/png" })] });

  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent className="flex max-h-[min(98dvh,1200px)] min-h-[min(88dvh,920px)] w-full max-w-[calc(100%-0.75rem)] flex-col gap-3 overflow-y-auto sm:max-w-7xl">
        <DialogHeader className="shrink-0 space-y-1 pb-0">
          <DialogTitle>生成邀请海报</DialogTitle>
          <p className="text-meta text-muted-foreground">好友通过你的链接注册，可领取新人礼包</p>
        </DialogHeader>

        <div className="grid min-h-0 flex-1 items-center gap-4 lg:grid-cols-[minmax(180px,220px)_minmax(0,1fr)_minmax(96px,112px)]">
          <div className="space-y-5 self-start">
            <section>
              <StepLabel n={1}>选择海报样式</StepLabel>
              <div className="flex flex-col gap-2">
                {POSTER_TEMPLATES.map((t) => (
                  <button
                    key={t.id}
                    type="button"
                    onClick={() => setConfig((c) => ({ ...c, template: t }))}
                    className={cn(
                      "rounded-xl px-3 py-2.5 text-left ring-1 transition-colors",
                      config.template.id === t.id
                        ? "bg-primary-soft font-medium text-primary ring-primary/40"
                        : "text-muted-foreground ring-border hover:text-foreground",
                    )}
                  >
                    <div className="text-meta">{t.name}</div>
                    <div className="mt-0.5 text-caption opacity-80">{t.blurb}</div>
                  </button>
                ))}
              </div>
            </section>

            <div className="flex flex-col gap-2 pt-1">
              <Button className="w-full" size="lg" onClick={download}>
                <Download /> 下载海报
              </Button>
              {canShareFile && (
                <Button variant="outline" className="w-full" size="lg" onClick={share}>
                  <Share2 /> 分享给好友
                </Button>
              )}
            </div>
          </div>

          {/* 中：宽度 100%，内部按可用宽度缩放，防窄屏横向溢出 */}
          <div
            ref={previewSlotRef}
            className="flex min-h-0 min-w-0 w-full flex-col items-center justify-center self-stretch overflow-x-hidden"
            data-testid="poster-preview-slot"
          >
            <ScaledPoster
              config={config}
              link={link}
              inviteCode={inviteCode}
              scale={previewScale}
              testId="poster-preview"
            />
          </div>

          <div className="hidden self-center lg:flex lg:flex-col lg:items-center lg:gap-2.5">
            <div className="text-meta font-medium text-foreground">更多样式</div>
            {POSTER_TEMPLATES.map((t) => {
              const thumbConfig: PosterConfig = { ...config, template: t };
              const active = config.template.id === t.id;
              return (
                <button
                  key={t.id}
                  type="button"
                  onClick={() => setConfig((c) => ({ ...c, template: t }))}
                  className={cn(
                    "flex w-full flex-col items-center rounded-xl p-1 transition-shadow",
                    active ? "shadow-md ring-2 ring-primary" : "ring-1 ring-border hover:ring-primary/40",
                  )}
                  aria-label={`样式 ${t.name}`}
                >
                  <ScaledPoster config={thumbConfig} link={link} inviteCode={inviteCode} scale={THUMB_SCALE} />
                  <div className="mt-1 text-center text-caption text-muted-foreground">{t.name}</div>
                </button>
              );
            })}
          </div>
        </div>
      </DialogContent>
    </Dialog>
  );
};
