"use client";

import { useEffect, useMemo, useState } from "react";
import type {
  GenerateMeta,
  GeneratedImage,
  PublicUser,
  QuotaSnapshot,
} from "@/lib/types";

const QUICK_PROMPTS = [
  "一款银白色耳机悬浮在纯白背景中，柔和边缘光，苹果官网产品摄影质感。",
  "安静的极简客厅，浅木地板，大窗户自然光，室内设计杂志封面风格。",
  "未来感城市夜景中的电动车，低饱和电影光影，写实概念海报。",
];

const PROCESSING_STAGES = [
  "验证账号和额度",
  "发送 Prompt 到 gpt-image-2",
  "等待模型渲染图像",
  "整理图片并准备下载",
];

type StudioStatus = "idle" | "pending" | "success" | "error";

type StudioResult = GeneratedImage & {
  previewUrl: string;
};

type NotificationPermissionState = NotificationPermission | "unsupported";
type ServiceWorkerStatus = "checking" | "ready" | "error";

interface BeforeInstallPromptEvent extends Event {
  prompt(): Promise<void>;
  userChoice: Promise<{
    outcome: "accepted" | "dismissed";
    platform: string;
  }>;
}

interface GenerateResponse {
  ok?: boolean;
  error?: string;
  images?: GeneratedImage[];
  meta?: GenerateMeta;
  quota?: QuotaSnapshot;
}

interface StudioClientProps {
  currentUser: PublicUser;
  initialQuota: QuotaSnapshot;
}

interface ProcessingCardProps {
  status: StudioStatus;
  startedAt: number;
}

interface PwaFeedback {
  tone: "success" | "error";
  message: string;
}

function getErrorMessage(error: unknown, fallbackMessage: string): string {
  return error instanceof Error ? error.message : fallbackMessage;
}

function truncateText(text: string, maxLength: number): string {
  if (text.length <= maxLength) {
    return text;
  }

  return `${text.slice(0, maxLength - 1)}...`;
}

function getIsStandaloneMode(): boolean {
  if (typeof window === "undefined") {
    return false;
  }

  const iosStandalone = Boolean(
    (window.navigator as Navigator & { standalone?: boolean }).standalone,
  );

  return window.matchMedia("(display-mode: standalone)").matches || iosStandalone;
}

async function showGenerationNotification({
  prompt,
  image,
  meta,
}: {
  prompt: string;
  image: GeneratedImage;
  meta: GenerateMeta | null;
}): Promise<void> {
  if (typeof window === "undefined" || !("Notification" in window)) {
    return;
  }

  if (Notification.permission !== "granted") {
    return;
  }

  const details = [
    meta?.model,
    meta?.size,
    meta?.durationMs ? `${meta.durationMs} ms` : null,
  ].filter(Boolean);
  const body = [truncateText(prompt, 42), details.join(" · ")]
    .filter(Boolean)
    .join(" | ");
  const options: NotificationOptions = {
    body,
    icon: "/pwa-icon.svg",
    badge: "/pwa-badge.svg",
    tag: `generation-${image.id}`,
    data: {
      url: "/studio",
    },
  };

  if ("serviceWorker" in navigator) {
    const registration = await navigator.serviceWorker.ready;
    await registration.showNotification("图片生成完成", options);
    return;
  }

  const notification = new Notification("图片生成完成", options);
  notification.onclick = () => {
    window.focus();
    window.location.href = "/studio";
  };
}

export default function StudioClient({
  currentUser,
  initialQuota,
}: StudioClientProps) {
  const [prompt, setPrompt] = useState("");
  const [status, setStatus] = useState<StudioStatus>("idle");
  const [errorMessage, setErrorMessage] = useState("");
  const [requestMeta, setRequestMeta] = useState<GenerateMeta | null>(null);
  const [result, setResult] = useState<StudioResult | null>(null);
  const [quota, setQuota] = useState(initialQuota);
  const [startedAt, setStartedAt] = useState(0);
  const [serviceWorkerStatus, setServiceWorkerStatus] =
    useState<ServiceWorkerStatus>("checking");
  const [notificationPermission, setNotificationPermission] =
    useState<NotificationPermissionState>("default");
  const [installPromptEvent, setInstallPromptEvent] =
    useState<BeforeInstallPromptEvent | null>(null);
  const [isStandalone, setIsStandalone] = useState(false);
  const [pwaFeedback, setPwaFeedback] = useState<PwaFeedback | null>(null);

  useEffect(() => {
    if (typeof window === "undefined") {
      return undefined;
    }

    setNotificationPermission(
      "Notification" in window ? Notification.permission : "unsupported",
    );
    setIsStandalone(getIsStandaloneMode());

    const handleBeforeInstallPrompt = (event: Event) => {
      event.preventDefault();
      setInstallPromptEvent(event as BeforeInstallPromptEvent);
    };
    const handleAppInstalled = () => {
      setInstallPromptEvent(null);
      setIsStandalone(true);
      setPwaFeedback({
        tone: "success",
        message: "应用已安装完成，之后可以直接从桌面或启动器打开。",
      });
    };

    window.addEventListener("beforeinstallprompt", handleBeforeInstallPrompt);
    window.addEventListener("appinstalled", handleAppInstalled);

    if (!("serviceWorker" in navigator)) {
      setServiceWorkerStatus("error");

      return () => {
        window.removeEventListener(
          "beforeinstallprompt",
          handleBeforeInstallPrompt,
        );
        window.removeEventListener("appinstalled", handleAppInstalled);
      };
    }

    navigator.serviceWorker
      .register("/sw.js")
      .then(async () => {
        await navigator.serviceWorker.ready;
        setServiceWorkerStatus("ready");
      })
      .catch(() => {
        setServiceWorkerStatus("error");
      });

    return () => {
      window.removeEventListener("beforeinstallprompt", handleBeforeInstallPrompt);
      window.removeEventListener("appinstalled", handleAppInstalled);
    };
  }, []);

  const promptStats = useMemo(() => {
    const cleanPrompt = prompt.trim();

    if (!cleanPrompt) {
      return "输入一句尽可能具体的画面描述即可。";
    }

    return `${cleanPrompt.length} 个字符`;
  }, [prompt]);

  const serviceWorkerLabel = useMemo(() => {
    if (serviceWorkerStatus === "ready") {
      return "已就绪";
    }

    if (serviceWorkerStatus === "error") {
      return "不可用";
    }

    return "注册中";
  }, [serviceWorkerStatus]);

  const notificationLabel = useMemo(() => {
    if (notificationPermission === "granted") {
      return "已开启";
    }

    if (notificationPermission === "denied") {
      return "已拒绝";
    }

    if (notificationPermission === "unsupported") {
      return "浏览器不支持";
    }

    return "等待授权";
  }, [notificationPermission]);

  const installLabel = useMemo(() => {
    if (isStandalone) {
      return "已作为应用运行";
    }

    if (installPromptEvent) {
      return "可直接安装";
    }

    return "可通过浏览器菜单安装";
  }, [installPromptEvent, isStandalone]);

  async function handleInstallApp(): Promise<void> {
    if (isStandalone) {
      setPwaFeedback({
        tone: "success",
        message: "当前已经在 PWA 模式下运行。",
      });
      return;
    }

    if (!installPromptEvent) {
      setPwaFeedback({
        tone: "error",
        message:
          "当前浏览器没有暴露安装弹窗，可以使用地址栏或浏览器菜单中的“安装应用/添加到主屏幕”。",
      });
      return;
    }

    await installPromptEvent.prompt();
    const choice = await installPromptEvent.userChoice;

    setPwaFeedback({
      tone: choice.outcome === "accepted" ? "success" : "error",
      message:
        choice.outcome === "accepted"
          ? "浏览器已接受安装请求，应用会加入桌面或启动器。"
          : "这次没有完成安装，你之后仍然可以再次安装。",
    });
    setInstallPromptEvent(null);
  }

  async function handleEnableNotifications(): Promise<void> {
    if (!("Notification" in window)) {
      setNotificationPermission("unsupported");
      setPwaFeedback({
        tone: "error",
        message: "当前浏览器不支持系统通知。",
      });
      return;
    }

    if (Notification.permission === "denied") {
      setNotificationPermission("denied");
      setPwaFeedback({
        tone: "error",
        message: "通知权限已被拒绝，请在浏览器的站点设置里手动重新开启。",
      });
      return;
    }

    const permission = await Notification.requestPermission();
    setNotificationPermission(permission);

    setPwaFeedback({
      tone: permission === "granted" ? "success" : "error",
      message:
        permission === "granted"
          ? "系统通知已开启，图片生成成功后会立刻提醒你。"
          : "你还没有授予通知权限，本次不会发送系统通知。",
    });
  }

  async function handleGenerate(): Promise<void> {
    const cleanPrompt = prompt.trim();

    if (!cleanPrompt) {
      setErrorMessage("请输入 Prompt 后再开始生成。");
      return;
    }

    setStatus("pending");
    setErrorMessage("");
    setResult(null);
    setRequestMeta(null);
    setStartedAt(Date.now());

    try {
      const response = await fetch("/api/generate", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          prompt: cleanPrompt,
          size: "1024x1024",
          quality: "high",
          outputFormat: "png",
          background: "auto",
          count: 1,
          moderation: "auto",
        }),
      });
      const payload = (await response.json()) as GenerateResponse;

      if (!response.ok || payload.ok !== true) {
        throw new Error(payload.error || "生成失败，请稍后重试。");
      }

      const image = payload.images?.[0];

      if (!image) {
        throw new Error("没有拿到可用图片。");
      }

      setResult({
        ...image,
        previewUrl: `data:${image.mimeType};base64,${image.base64}`,
      });
      setRequestMeta(payload.meta ?? null);
      setQuota(payload.quota ?? initialQuota);
      setStatus("success");

      try {
        await showGenerationNotification({
          prompt: cleanPrompt,
          image,
          meta: payload.meta ?? null,
        });
      } catch {
        setPwaFeedback({
          tone: "error",
          message: "图片已生成成功，但系统通知发送失败，请刷新后重试。",
        });
      }
    } catch (error) {
      setErrorMessage(getErrorMessage(error, "生成失败，请稍后重试。"));
      setStatus("error");
    }
  }

  function handleDownload() {
    if (!result) {
      return;
    }

    const blob = base64ToBlob(result.base64, result.mimeType);
    const blobUrl = URL.createObjectURL(blob);
    const anchor = document.createElement("a");

    anchor.href = blobUrl;
    anchor.download = result.fileName;
    anchor.click();

    window.setTimeout(() => URL.revokeObjectURL(blobUrl), 2000);
  }

  return (
    <div className="studio-grid">
      <section className="card composer-card">
        <div className="section-heading">
          <div>
            <p className="section-kicker">Prompt</p>
            <h3>Describe your image</h3>
          </div>
          <span className="subtle-pill">
            {quota.isUnlimited
              ? "Unlimited"
              : `剩余 ${quota.remaining} / ${quota.limit}`}
          </span>
        </div>

        <div className="pwa-panel">
          <div>
            <p className="section-kicker">PWA</p>
            <h4>安装应用并接收生成完成通知</h4>
            <p className="block-copy">
              允许通知后，当前页面调用 <code>/api/generate</code>{" "}
              成功返回图片时，会通过 Service Worker 发送系统提醒。
            </p>
          </div>

          <div className="pwa-status-grid">
            <div className="pwa-status-card">
              <span>应用状态</span>
              <strong>{installLabel}</strong>
            </div>
            <div className="pwa-status-card">
              <span>通知权限</span>
              <strong>{notificationLabel}</strong>
            </div>
            <div className="pwa-status-card">
              <span>Service Worker</span>
              <strong>{serviceWorkerLabel}</strong>
            </div>
          </div>

          <div className="pwa-actions">
            <button
              type="button"
              className="ghost-button"
              onClick={handleInstallApp}
              disabled={isStandalone}
            >
              {isStandalone ? "已安装" : "安装应用"}
            </button>
            <button
              type="button"
              className="ghost-button"
              onClick={handleEnableNotifications}
              disabled={notificationPermission === "granted"}
            >
              {notificationPermission === "granted"
                ? "通知已开启"
                : "开启通知"}
            </button>
          </div>

          {pwaFeedback ? (
            <div
              className={
                pwaFeedback.tone === "success"
                  ? "success-banner"
                  : "error-banner"
              }
            >
              {pwaFeedback.message}
            </div>
          ) : null}
        </div>

        <label className="field">
          <span>画面描述</span>
          <textarea
            rows={8}
            value={prompt}
            onChange={(event) => setPrompt(event.target.value)}
            placeholder="例如：一台银白色笔记本电脑放在浅灰色桌面上，清晨自然光从左侧落下，极简静物摄影，细节干净，像苹果官网产品页。"
          />
        </label>

        <div className="composer-meta">
          <span>{promptStats}</span>
          <span className="muted">
            {currentUser.role === "admin"
              ? "管理员不会被扣减额度"
              : `当前计费周期：${quota.periodKey}`}
          </span>
        </div>

        <div className="quick-prompt-list">
          {QUICK_PROMPTS.map((item) => (
            <button
              key={item}
              type="button"
              className="ghost-chip"
              onClick={() => setPrompt(item)}
            >
              {item}
            </button>
          ))}
        </div>

        {errorMessage ? (
          <div className="error-banner">{errorMessage}</div>
        ) : null}

        <div className="composer-actions">
          <div className="meta-pills">
            <span>Default size 1024</span>
            <span>PNG</span>
            <span>High quality</span>
          </div>
          <button
            type="button"
            className="primary-button"
            onClick={handleGenerate}
            disabled={status === "pending"}
          >
            {status === "pending" ? "生成中..." : "生成图片"}
          </button>
        </div>
      </section>

      <ProcessingCard key={startedAt} status={status} startedAt={startedAt} />

      <section className="card result-card">
        <div className="section-heading">
          <div>
            <p className="section-kicker">Result</p>
            <h3>生成结果</h3>
          </div>
          <button
            type="button"
            className="ghost-button"
            disabled={!result}
            onClick={handleDownload}
          >
            下载图片
          </button>
        </div>

        <p className="muted block-copy">
          {requestMeta
            ? `${requestMeta.model} · ${requestMeta.size} · ${requestMeta.outputFormat.toUpperCase()} · ${requestMeta.durationMs} ms`
            : "生成完成后会在这里显示耗时和图片。"}
        </p>

        {result ? (
          <div className="result-stack">
            <div className="image-frame">
              <img
                src={result.previewUrl}
                alt={result.fileName}
                width="1024"
                height="1024"
              />
            </div>
            {result.revisedPrompt ? (
              <div className="result-copy">
                <span className="result-caption">模型调整后的 Prompt</span>
                <p>{result.revisedPrompt}</p>
              </div>
            ) : null}
          </div>
        ) : (
          <div className="result-placeholder">
            <div className="placeholder-orb" />
            <h4>结果会出现在这里</h4>
            <p>滚动性能已收敛优化，结果区只在真正返回图片时更新。</p>
          </div>
        )}
      </section>
    </div>
  );
}

function ProcessingCard({ status, startedAt }: ProcessingCardProps) {
  const [elapsedMs, setElapsedMs] = useState(0);

  useEffect(() => {
    if (status !== "pending") {
      return undefined;
    }

    const timer = window.setInterval(() => {
      setElapsedMs(Date.now() - startedAt);
    }, 220);

    return () => window.clearInterval(timer);
  }, [status, startedAt]);

  const progressSnapshot = useMemo(() => {
    if (status === "success") {
      return {
        progress: 100,
        activeIndex: PROCESSING_STAGES.length - 1,
        lead: "图片已生成完成，可以直接查看和下载。",
      };
    }

    if (status === "error") {
      return {
        progress: 0,
        activeIndex: -1,
        lead: "本次生成未完成，请检查 Prompt 或额度后重试。",
      };
    }

    if (status !== "pending") {
      return {
        progress: 0,
        activeIndex: -1,
        lead: "准备就绪，输入 Prompt 后即可开始生成。",
      };
    }

    const progress = Math.min(92, Math.round(elapsedMs / 250));
    const activeIndex = Math.min(
      PROCESSING_STAGES.length - 1,
      Math.floor(elapsedMs / 5000),
    );

    return {
      progress,
      activeIndex,
      lead: `处理中：${PROCESSING_STAGES[activeIndex]}`,
    };
  }, [elapsedMs, status]);

  return (
    <section className="card processing-card">
      <div className="section-heading">
        <div>
          <p className="section-kicker">Processing</p>
          <h3>等待过程</h3>
        </div>
        <span className="subtle-pill">
          {status === "pending"
            ? "进行中"
            : status === "success"
              ? "完成"
              : status === "error"
                ? "失败"
                : "待命"}
        </span>
      </div>

      <p className="block-copy">{progressSnapshot.lead}</p>

      <div className="progress-track" aria-hidden="true">
        <div
          className="progress-fill"
          style={{ width: `${progressSnapshot.progress}%` }}
        />
      </div>

      <ol className="processing-list">
        {PROCESSING_STAGES.map((stage, index) => {
          const isDone =
            status === "success" || index < progressSnapshot.activeIndex;
          const isActive =
            status === "pending" && index === progressSnapshot.activeIndex;

          return (
            <li
              key={stage}
              className={
                isDone
                  ? "processing-item processing-item-done"
                  : isActive
                    ? "processing-item processing-item-active"
                    : "processing-item"
              }
            >
              <div className="step-dot" />
              <span>{stage}</span>
            </li>
          );
        })}
      </ol>
    </section>
  );
}

function base64ToBlob(base64: string, mimeType: string): Blob {
  const binary = atob(base64);
  const bytes = new Uint8Array(binary.length);

  for (let index = 0; index < binary.length; index += 1) {
    bytes[index] = binary.charCodeAt(index);
  }

  return new Blob([bytes], { type: mimeType });
}
