// Launch campaign hub: goals, social matrix, referral links and campaign tracking.
const LAUNCH_ATTR_KEY = "dz_launch_attribution_v1";
const LAUNCH_CLIENT_KEY = "dz_launch_client_v1";

function cleanLaunchToken(value, max = 80) {
  return String(value || "").trim().replace(/[^\u4e00-\u9fa5A-Za-z0-9_.:-]/g, "").slice(0, max);
}

function launchHashParams() {
  const raw = String(location.hash || "");
  const q = raw.includes("?") ? raw.slice(raw.indexOf("?") + 1) : "";
  return new URLSearchParams(q);
}

function readLaunchAttribution() {
  const search = new URLSearchParams(location.search || "");
  const hash = launchHashParams();
  let saved = {};
  try { saved = JSON.parse(localStorage.getItem(LAUNCH_ATTR_KEY) || "{}"); } catch (e) {}
  const next = {
    ref: cleanLaunchToken(search.get("ref") || hash.get("ref") || saved.ref || ""),
    campaign: cleanLaunchToken(search.get("utm_campaign") || hash.get("campaign") || saved.campaign || ""),
    channel: cleanLaunchToken(search.get("utm_source") || hash.get("channel") || saved.channel || ""),
  };
  if (next.ref || next.campaign || next.channel) {
    try { localStorage.setItem(LAUNCH_ATTR_KEY, JSON.stringify({ ...next, at: new Date().toISOString() })); } catch (e) {}
  }
  return next;
}

function launchClientId() {
  let id = "";
  try { id = localStorage.getItem(LAUNCH_CLIENT_KEY) || ""; } catch (e) {}
  if (!id) {
    id = "launch-" + Math.random().toString(36).slice(2) + Date.now().toString(36);
    try { localStorage.setItem(LAUNCH_CLIENT_KEY, id); } catch (e) {}
  }
  return id;
}

function launchShareCode(session) {
  const raw = session?.username || session?.displayName || launchClientId();
  return cleanLaunchToken(raw, 32) || "zootown";
}

function launchShareUrl(campaignId = "", refCode = "") {
  const url = new URL(location.origin + location.pathname);
  if (refCode) url.searchParams.set("ref", refCode);
  if (campaignId) url.searchParams.set("utm_campaign", campaignId);
  url.searchParams.set("utm_source", "share");
  url.hash = "launch";
  return url.toString();
}

function localLaunchStats() {
  const state = window.dzStore?.get?.() || {};
  const sightings = state.sightings || [];
  const contributors = new Set();
  sightings.forEach(item => {
    const key = String(item.contributor || item.contact || item.id || "").trim().toLowerCase();
    if (key) contributors.add(key);
  });
  const nominations = window.dzNaming?.localNominations?.() || [];
  return {
    activeUsers: Math.max(contributors.size, (state.contributors || []).length),
    uploads: sightings.length,
    nominations: nominations.length,
    verified: sightings.filter(x => ["已归档", "archived"].includes(x.status)).length,
    source: "local",
  };
}

async function fetchLaunchStats() {
  try {
    const resp = await fetch("/api/app/launch/stats", { credentials: "same-origin" });
    const json = await resp.json().catch(() => ({}));
    if (resp.ok && json.ok) return { ...json.stats, source: "server" };
  } catch (e) {}
  return localLaunchStats();
}

async function trackLaunchEvent(eventType, detail = {}) {
  const attribution = readLaunchAttribution();
  try {
    await fetch("/api/app/launch/events", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      credentials: "same-origin",
      body: JSON.stringify({
        eventType,
        campaign: detail.campaign || attribution.campaign || "",
        channel: detail.channel || attribution.channel || "",
        ref: detail.ref || attribution.ref || "",
        clientId: launchClientId(),
        detail,
      }),
    });
  } catch (e) {}
}

window.dzLaunch = {
  getAttribution: readLaunchAttribution,
  clientId: launchClientId,
  track: trackLaunchEvent,
  shareUrl: launchShareUrl,
};

function LaunchPage({ onNav }) {
  const config = window.LAUNCH_CAMPAIGN_CONFIG || {};
  const session = window.dzAuth?.getSession?.() || null;
  const [stats, setStats] = React.useState(() => localLaunchStats());
  const [copied, setCopied] = React.useState("");
  const [activeCampaign, setActiveCampaign] = React.useState(config.campaigns?.[0]?.id || "");
  const campaign = (config.campaigns || []).find(x => x.id === activeCampaign) || (config.campaigns || [])[0] || {};
  const refCode = launchShareCode(session);
  const shareUrl = launchShareUrl(campaign.id, refCode);
  const targets = config.targets || {};
  const targetCards = [
    { key: "activeUsers", label: "活跃市民", unit: "人", help: "首批稳定参与者" },
    { key: "uploads", label: "上传图片", unit: "张", help: "建立基础图像库" },
    { key: "nominations", label: "命名提案", unit: "个", help: "形成可分享卡片" },
    { key: "verified", label: "审核归档", unit: "条", help: "沉淀可信数据" },
  ];

  React.useEffect(() => {
    readLaunchAttribution();
    trackLaunchEvent("launch_page_view", { campaign: activeCampaign || "launch" });
    fetchLaunchStats().then(setStats);
  }, []);

  const progress = (key) => {
    const target = Number(targets[key] || 1);
    const value = Number(stats[key] || 0);
    return Math.max(0, Math.min(100, Math.round(value / target * 100)));
  };

  const copyInvite = async (text = "") => {
    const body = [text || campaign.shareText || config.hero?.subtitle, shareUrl, config.hashtag, ...(config.secondaryHashtags || []).slice(0, 2)].filter(Boolean).join("\n");
    try {
      await navigator.clipboard?.writeText(body);
      setCopied("邀请文案已复制，可以直接发到社群或朋友圈。");
    } catch (e) {
      setCopied("复制失败，可以手动复制页面上的邀请链接。");
    }
    trackLaunchEvent("campaign_share", { campaign: campaign.id, channel: "copy" });
  };

  const nativeShare = async () => {
    if (!navigator.share) {
      copyInvite();
      return;
    }
    try {
      await navigator.share({
        title: "达里尼动物城上线共建季",
        text: campaign.shareText || config.hero?.subtitle,
        url: shareUrl,
      });
      trackLaunchEvent("campaign_share", { campaign: campaign.id, channel: "native" });
    } catch (e) {}
  };

  return (
    <div className="page launch-page">
      <section className="launch-hero">
        <div className="app launch-hero-grid">
          <div>
            <div className="kicker"><span className="dot">●</span>{config.hero?.kicker || "PUBLIC LAUNCH"}</div>
            <h1 className="serif">{config.hero?.title}</h1>
            <p>{config.hero?.subtitle}</p>
            <div className="launch-actions">
              <button className="btn btn-lg btn-accent" onClick={() => { trackLaunchEvent("launch_cta_upload", { campaign: campaign.id }); onNav("upload"); }}>
                {config.hero?.primaryCta || "上传"}
              </button>
              <button className="btn btn-lg btn-ghost" onClick={() => copyInvite()}>
                {config.hero?.secondaryCta || "复制邀请链接"}
              </button>
              <button className="btn btn-lg btn-ghost" onClick={nativeShare}>系统分享</button>
            </div>
            {copied && <div className="launch-copy-note">{copied}</div>}
            <div className="launch-metric-strip" aria-label="上线目标">
              {targetCards.map(item => (
                <div key={item.key}>
                  <strong>{Number(targets[item.key] || 0)}{item.unit}</strong>
                  <span>{item.label}</span>
                  <small>{item.help}</small>
                </div>
              ))}
            </div>
          </div>
          <div className="launch-scoreboard">
            <div className="launch-scoreboard-head">
              <span>{config.windowLabel}</span>
              <strong>{stats.source === "server" ? "真实数据" : "本地预览"}</strong>
            </div>
            {targetCards.map(row => (
              <div className="launch-goal-row" key={row.key}>
                <div>
                  <b>{row.label}</b>
                  <span>{Number(stats[row.key] || 0)} / {Number(targets[row.key] || 0)} {row.unit}</span>
                </div>
                <em style={{ width: progress(row.key) + "%" }}></em>
              </div>
            ))}
            <div className="launch-invite-box">
              <span>你的邀请码</span>
              <strong>{refCode}</strong>
              <input readOnly value={shareUrl} onFocus={e => e.target.select()} />
            </div>
          </div>
        </div>
      </section>

      <section className="section launch-campaign-section">
        <div className="app">
          <div className="section-head">
            <div>
              <div className="kicker mb-4"><span className="dot">●</span>CAMPAIGNS / 四个首发活动</div>
              <h2 className="serif">把“上传照片”变成可传播的连续动作。</h2>
            </div>
            <button className="btn btn-accent" onClick={() => onNav(campaign.route || "upload")}>进入当前活动</button>
          </div>
          <div className="launch-campaign-grid">
            {(config.campaigns || []).map(item => (
              <button
                key={item.id}
                className={"launch-campaign-card" + (item.id === activeCampaign ? " active" : "")}
                aria-pressed={item.id === activeCampaign}
                onClick={() => setActiveCampaign(item.id)}
              >
                <span>{item.badge}</span>
                <h3>{item.title}</h3>
                <p>{item.hook}</p>
                <small>{item.channel === "all" ? "全平台承接" : item.channel}</small>
              </button>
            ))}
          </div>
          <div className="launch-campaign-detail">
            <div>
              <span className="launch-detail-badge">{campaign.badge}</span>
              <h3>{campaign.title}</h3>
              <p>{campaign.hook}</p>
              <div className="launch-detail-actions">
                <button className="btn btn-accent" onClick={() => { trackLaunchEvent("campaign_cta", { campaign: campaign.id }); onNav(campaign.route || "upload"); }}>参与活动</button>
                <button className="btn btn-ghost" onClick={() => copyInvite(campaign.shareText)}>复制该活动文案</button>
              </div>
            </div>
            <ol>
              {(campaign.mechanic || []).map((step, i) => <li key={i}>{step}</li>)}
            </ol>
            <div className="launch-reward">
              <b>激励机制</b>
              <span>{campaign.reward}</span>
            </div>
          </div>
        </div>
      </section>

      <section className="section launch-matrix-section">
        <div className="app launch-two-col">
          <div>
            <div className="kicker mb-4"><span className="dot">●</span>SOCIAL MATRIX / 宣发矩阵</div>
            <h2 className="serif">不同平台承担不同增长任务。</h2>
            <div className="launch-channel-list">
              {(config.socialMatrix || []).map(channel => (
                <div className="launch-channel" key={channel.id}>
                  <div>
                    <strong>{channel.name}</strong>
                    <span>{channel.role}</span>
                  </div>
                  <p>{channel.cadence} · {channel.format}</p>
                  <small>{(channel.seedTopics || []).join(" / ")}</small>
                </div>
              ))}
            </div>
          </div>
          <div>
            <div className="launch-template-box">
              <h3>可直接发布的文案</h3>
              {(config.postTemplates || []).map(tpl => (
                <div key={tpl.id} className="launch-template">
                  <b>{tpl.channel} · {tpl.title}</b>
                  <p>{tpl.body}</p>
                  <button className="btn btn-sm btn-ghost" onClick={() => copyInvite(tpl.body)}>复制</button>
                </div>
              ))}
            </div>
            <div className="launch-guardrails">
              <h3>传播底线</h3>
              {(config.guardrails || []).map(rule => <span key={rule}>{rule}</span>)}
            </div>
          </div>
        </div>
      </section>

      <section className="section launch-quest-section">
        <div className="app">
          <div className="section-head">
            <div>
              <div className="kicker mb-4"><span className="dot">●</span>QUESTS / 首批用户任务</div>
              <h2 className="serif">给种子用户一条清楚的参与路径。</h2>
            </div>
          </div>
          <div className="launch-quest-grid">
            {(config.quests || []).map((quest, i) => (
              <button key={quest.id} className="launch-quest" onClick={() => onNav(quest.route || "upload")}>
                <em>{String(i + 1).padStart(2, "0")}</em>
                <strong>{quest.title}</strong>
                <span>{quest.points} pts</span>
              </button>
            ))}
          </div>
        </div>
      </section>
    </div>
  );
}
