// BEGIN CHANGE: pagina Shop System (cards + compra PP + historico)
"use client";

import { FormEvent, useCallback, useEffect, useMemo, useState } from "react";
import Link from "next/link";
import { useI18n } from "@/i18n/LanguageProvider";
import { useAuth } from "@/auth/AuthProvider";
import { Navbar } from "@/components/Navbar";
import { Footer } from "@/components/Footer";
import { ItemIcon } from "@/components/ItemIcon";
import { ShopHistorySerials, ShopHistoryWhat } from "@/components/ShopHistoryWhat";
import { apiUrl } from "@/lib/api";

type ShopIcon = { itemId: number; count: number; kind: string };
type BundleItem = { itemId: number; count: number };
type BundleOption = { id: number; label: string; items: BundleItem[] };
type BundleGroup = {
  id: number;
  label: string;
  minSelect: number;
  maxSelect: number;
  options: BundleOption[];
};
type Offer = {
  id: number;
  offerType: string;
  section: string;
  name: string;
  descriptionHtml: string;
  points: number;
  icons: ShopIcon[];
  days: number;
  needsChoice?: boolean;
  groups?: BundleGroup[];
  bundle?: { groups: BundleGroup[] };
  // BEGIN CHANGE: optional purchase quantity
  allowQuantity?: number;
  maxQuantity?: number;
  // END CHANGE
};
type Section = { id: string; offers: Offer[] };
type HistoryRow = {
  kind: string;
  id: number;
  toName: string;
  price: number;
  state: string;
  started: number;
  realized: number;
  itemName: string;
  days: number;
  offerId: number;
  catalog?: string;
  // BEGIN CHANGE: serial on history
  serialItem?: string;
  // END CHANGE
  // BEGIN CHANGE: resolved items for icons
  items?: { itemId: number; count: number; name: string }[];
  // END CHANGE
};
type CharOpt = { name: string; level: number; vocation: string; online?: boolean };

// BEGIN CHANGE: player shop stats
type ShopPlayerStats = {
  waiting: number;
  spent30d: number;
  lastBuy: number;
};
// END CHANGE

type Catalog = "donate" | "guild";

type Payload = {
  catalog?: Catalog;
  sections: Section[];
  premiumPoints: number | null;
  guildPoints: number | null;
  characters: CharOpt[];
  history: HistoryRow[];
  deliveryHint: string;
  // BEGIN CHANGE: player shop stats
  stats?: ShopPlayerStats | null;
  // END CHANGE
};

function sectionLabel(
  id: string,
  labels: {
    sectionUpgrade: string;
    sectionPackages: string;
    sectionWeapons: string;
    sectionConsumables: string;
    sectionImbuements: string;
    sectionItems: string;
  }
): string {
  const map: Record<string, string> = {
    upgrade: labels.sectionUpgrade,
    packages: labels.sectionPackages,
    weapons: labels.sectionWeapons,
    consumables: labels.sectionConsumables,
    imbuements: labels.sectionImbuements,
    items: labels.sectionItems,
  };
  return map[id] || id;
}

export default function ShopPage() {
  const { t } = useI18n();
  const { ready, token, account } = useAuth();
  const [status, setStatus] = useState<"loading" | "ok" | "error">("loading");
  const [data, setData] = useState<Payload | null>(null);
  // BEGIN CHANGE: aba Shop Donate (PP) vs Shop Guild (GP)
  const [catalog, setCatalog] = useState<Catalog>("donate");
  // END CHANGE
  const [section, setSection] = useState<string>("all");
  const [query, setQuery] = useState("");
  const [selected, setSelected] = useState<Offer | null>(null);
  const [destMode, setDestMode] = useState<"own" | "other">("own");
  const [playerName, setPlayerName] = useState("");
  const [busy, setBusy] = useState(false);
  const [msg, setMsg] = useState("");
  const [err, setErr] = useState("");
  const [confirmOpen, setConfirmOpen] = useState(false);
  // BEGIN CHANGE: wizard bundle (escolha por grupo)
  const [bundleStep, setBundleStep] = useState(0);
  const [bundlePicks, setBundlePicks] = useState<Record<number, number[]>>({});
  // END CHANGE
  // BEGIN CHANGE: optional purchase quantity
  const [buyQty, setBuyQty] = useState(1);
  // END CHANGE

  const pointsUnit = catalog === "guild" ? t.shop.unitGP : t.shop.unitPP;

  const authHeaders = useCallback(
    (json = true): HeadersInit => {
      const h: Record<string, string> = {};
      if (json) h["Content-Type"] = "application/json";
      if (token) h.Authorization = `Bearer ${token}`;
      return h;
    },
    [token]
  );

  const load = useCallback(() => {
    setStatus("loading");
    fetch(apiUrl(`shop.php?catalog=${catalog}`), { headers: authHeaders(false) })
      .then((r) => {
        if (!r.ok) throw new Error("http");
        return r.json();
      })
      .then((json: Payload) => {
        setData(json);
        setStatus("ok");
      })
      .catch(() => setStatus("error"));
  }, [authHeaders, catalog]);

  useEffect(() => {
    if (!ready) return;
    load();
  }, [ready, load]);

  useEffect(() => {
    setSection("all");
    setQuery("");
    setSelected(null);
    setConfirmOpen(false);
    setBundleStep(0);
    setBundlePicks({});
    setBuyQty(1);
    setMsg("");
    setErr("");
  }, [catalog]);

  const allOffers = useMemo(
    () => (data?.sections ?? []).flatMap((s) => s.offers),
    [data]
  );

  const needsChoice = !!(selected?.needsChoice || selected?.offerType === "bundle");
  // BEGIN CHANGE: optional purchase quantity helpers
  const qtyEnabled = !!(selected?.allowQuantity && selected.offerType !== "pacc");
  const qtyMax = Math.max(1, Math.min(100, selected?.maxQuantity || 100));
  const totalPrice = (selected?.points || 0) * (qtyEnabled ? buyQty : 1);
  // END CHANGE
  const bundleGroups = useMemo(() => {
    if (!selected || !needsChoice) return [];
    return selected.groups ?? selected.bundle?.groups ?? [];
  }, [selected, needsChoice]);

  // BEGIN CHANGE: set fixo (1 opcao) nao entra no wizard - so escolha de arma
  const isFixedGroup = useCallback((g: BundleGroup) => {
    return g.options.length === 1 && g.minSelect >= 1 && g.maxSelect <= 1;
  }, []);

  const chooserGroups = useMemo(
    () => bundleGroups.filter((g) => !isFixedGroup(g)),
    [bundleGroups, isFixedGroup]
  );

  const bundleChoicesValid = useMemo(() => {
    if (!needsChoice) return true;
    for (const g of bundleGroups) {
      const picked = bundlePicks[g.id] ?? [];
      if (picked.length < g.minSelect || picked.length > g.maxSelect) {
        return false;
      }
    }
    return bundleGroups.length > 0;
  }, [needsChoice, bundleGroups, bundlePicks]);
  // END CHANGE

  const filtered = useMemo(() => {
    const q = query.trim().toLowerCase();
    return allOffers.filter((o) => {
      if (section !== "all" && o.section !== section) return false;
      if (!q) return true;
      return (
        o.name.toLowerCase().includes(q) ||
        o.descriptionHtml.toLowerCase().includes(q) ||
        o.offerType.toLowerCase().includes(q)
      );
    });
  }, [allOffers, section, query]);

  function errLabel(code: string) {
    const map = t.shop.errors as Record<string, string>;
    return map[code] || t.shop.actionFailed;
  }

  function openBuy(o: Offer) {
    setSelected(o);
    setErr("");
    setMsg("");
    setConfirmOpen(false);
    setBundleStep(0);
    setBuyQty(1);
    // BEGIN CHANGE: pre-seleciona grupos fixos (ex.: set completo)
    const groups = o.groups ?? o.bundle?.groups ?? [];
    const initial: Record<number, number[]> = {};
    for (const g of groups) {
      if (g.options.length === 1 && g.minSelect >= 1 && g.maxSelect <= 1) {
        initial[g.id] = [g.options[0].id];
      }
    }
    setBundlePicks(initial);
    // END CHANGE
    // BEGIN CHANGE: destino = meus chars OU outro do servidor
    const chars = data?.characters ?? [];
    if (chars.length > 0) {
      setDestMode("own");
      setPlayerName(chars[0].name);
    } else {
      setDestMode("other");
      setPlayerName("");
    }
    // END CHANGE
  }

  function closeBuy() {
    setSelected(null);
    setConfirmOpen(false);
    setBundleStep(0);
    setBundlePicks({});
    setBuyQty(1);
    setErr("");
  }

  function toggleBundleOption(group: BundleGroup, optionId: number) {
    setBundlePicks((prev) => {
      const cur = prev[group.id] ?? [];
      const has = cur.includes(optionId);
      let next: number[];
      if (group.maxSelect <= 1) {
        next = has ? [] : [optionId];
      } else if (has) {
        next = cur.filter((id) => id !== optionId);
      } else if (cur.length >= group.maxSelect) {
        next = [...cur.slice(1), optionId];
      } else {
        next = [...cur, optionId];
      }
      return { ...prev, [group.id]: next };
    });
    setErr("");
  }

  function currentBundleGroupValid() {
    if (!needsChoice) return true;
    const g = chooserGroups[bundleStep];
    if (!g) return true;
    const picked = bundlePicks[g.id] ?? [];
    return picked.length >= g.minSelect && picked.length <= g.maxSelect;
  }

  async function doBuy() {
    if (!token || !selected) {
      setErr(t.shop.needLogin);
      return;
    }
    if (!playerName.trim()) {
      setErr(t.shop.errors.player_required);
      return;
    }
    if (needsChoice && !bundleChoicesValid) {
      setErr(t.shop.bundlePickRequired);
      return;
    }
    setBusy(true);
    setErr("");
    setMsg("");
    try {
      const body: Record<string, unknown> = {
        action: "buy",
        catalog,
        offerId: selected.id,
        playerName: playerName.trim(),
        confirmed: true,
      };
      // BEGIN CHANGE: optional purchase quantity
      if (qtyEnabled) {
        body.quantity = buyQty;
      }
      // END CHANGE
      if (needsChoice) {
        body.choices = bundleGroups.map((g) => ({
          groupId: g.id,
          optionIds: bundlePicks[g.id] ?? [],
        }));
      }
      const r = await fetch(apiUrl("shop.php"), {
        method: "POST",
        headers: authHeaders(true),
        body: JSON.stringify(body),
      });
      const json = await r.json().catch(() => ({}));
      if (!r.ok || !json.ok) {
        setErr(errLabel(typeof json.error === "string" ? json.error : "buy_failed"));
        setConfirmOpen(false);
        return;
      }
      setData((cur) =>
        cur
          ? {
              ...cur,
              premiumPoints:
                typeof json.premiumPoints === "number"
                  ? json.premiumPoints
                  : cur.premiumPoints,
              guildPoints:
                typeof json.guildPoints === "number"
                  ? json.guildPoints
                  : cur.guildPoints,
              history: json.history ?? cur.history,
              // BEGIN CHANGE: refresh player stats after buy
              stats: json.stats ?? cur.stats,
              // END CHANGE
            }
          : cur
      );
      setMsg(
        (json.delivery === "instant" ? t.shop.buyOkInstant : t.shop.buyOkQueue)
          .replace("{name}", json.offerName || selected.name)
          .replace("{player}", json.toName || playerName)
      );
      // BEGIN CHANGE: soft online tip after queue buy
      if (json.delivery === "queue" && json.toOnline === false) {
        setMsg((m) => `${m} ${t.shop.destOfflineHint}`);
      }
      // END CHANGE
      setConfirmOpen(false);
      setSelected(null);
      setBundleStep(0);
      setBundlePicks({});
      setBuyQty(1);
    } catch {
      setErr(t.shop.actionFailed);
    } finally {
      setBusy(false);
    }
  }

  function onSubmitBuy(e: FormEvent) {
    e.preventDefault();
    if (needsChoice && !bundleChoicesValid) {
      setErr(t.shop.bundlePickRequired);
      return;
    }
    setConfirmOpen(true);
  }

  function formatDate(ts: number) {
    if (!ts) return "-";
    return new Date(ts * 1000).toLocaleString();
  }

  const loggedIn = !!(ready && token && account);
  const sectionTabs = [
    { id: "all", label: t.shop.filterAll },
    ...(data?.sections ?? []).map((s) => ({
      id: s.id,
      label: sectionLabel(s.id, t.shop),
    })),
  ];

  return (
    <div className="flex min-h-screen flex-col">
      <Navbar />
      <main className="mx-auto w-full max-w-6xl flex-1 px-6 py-14">
        <div className="flex flex-wrap items-end justify-between gap-4">
          <div>
            <h1 className="text-3xl font-semibold tracking-tight">{t.shop.title}</h1>
            <p className="mt-2 text-muted">{t.shop.subtitle}</p>
          </div>
          {loggedIn && (
            <div className="space-y-1 text-sm text-right">
              {data?.premiumPoints != null && (
                <p>
                  {t.shop.yourPoints}:{" "}
                  <span className="font-semibold text-brand">{data.premiumPoints}</span>
                </p>
              )}
              {data?.guildPoints != null && (
                <p>
                  {t.shop.yourGuildPoints}:{" "}
                  <span className="font-semibold text-brand">{data.guildPoints}</span>
                </p>
              )}
            </div>
          )}
        </div>

        {!loggedIn && ready && (
          <p className="mt-4 text-sm text-muted">
            {t.shop.needLogin}{" "}
            <Link href="/login" className="text-brand hover:underline">
              {t.nav.items.login}
            </Link>
            {" / "}
            <Link href="/donate" className="text-brand hover:underline">
              {t.nav.items.donate}
            </Link>
          </p>
        )}

        {/* BEGIN CHANGE: seletor catalogo donate vs guild */}
        <div className="mt-6 flex flex-wrap gap-2">
          <button
            type="button"
            onClick={() => setCatalog("donate")}
            className={`rounded-lg border px-4 py-2 text-sm font-medium ${
              catalog === "donate"
                ? "border-brand/50 bg-brand/15 text-foreground"
                : "border-border text-muted hover:border-brand/30"
            }`}
          >
            {t.shop.tabDonate}
          </button>
          <button
            type="button"
            onClick={() => setCatalog("guild")}
            className={`rounded-lg border px-4 py-2 text-sm font-medium ${
              catalog === "guild"
                ? "border-brand/50 bg-brand/15 text-foreground"
                : "border-border text-muted hover:border-brand/30"
            }`}
          >
            {t.shop.tabGuild}
          </button>
        </div>
        {/* END CHANGE */}

        {msg && <p className="mt-4 text-sm text-brand">{msg}</p>}
        {err && !selected && <p className="mt-4 text-sm text-red-400">{err}</p>}

        <p className="mt-4 text-xs text-muted">{data?.deliveryHint || t.shop.deliveryHint}</p>

        <div className="mt-6 flex flex-wrap gap-2">
          {sectionTabs.map((tab) => (
            <button
              key={tab.id}
              type="button"
              onClick={() => setSection(tab.id)}
              className={`rounded-lg border px-3 py-1.5 text-sm ${
                section === tab.id
                  ? "border-brand/50 bg-brand/15 text-foreground"
                  : "border-border text-muted hover:border-brand/30"
              }`}
            >
              {tab.label}
            </button>
          ))}
        </div>

        <input
          value={query}
          onChange={(e) => setQuery(e.target.value)}
          placeholder={t.shop.searchPlaceholder}
          className="mt-4 w-full max-w-sm rounded-lg border border-border bg-panel px-4 py-2 text-sm outline-none focus:border-brand/60"
        />

        {status === "loading" && <p className="mt-8 text-muted">{t.common.loading}</p>}
        {status === "error" && <p className="mt-8 text-muted">{t.common.error}</p>}
        {status === "ok" && filtered.length === 0 && (
          <p className="mt-8 text-muted">{t.shop.empty}</p>
        )}

        {status === "ok" && filtered.length > 0 && (
          <div className="mt-8 grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
            {filtered.map((o) => (
              <button
                key={o.id}
                type="button"
                onClick={() => openBuy(o)}
                className="flex flex-col rounded-xl border border-border bg-panel p-4 text-left transition-colors hover:border-brand/40"
              >
                <div className="flex flex-wrap items-center gap-2">
                  {o.icons.length === 0 || o.offerType === "pacc" ? (
                    <span className="grid h-12 w-12 place-items-center rounded bg-background text-xs text-muted">
                      VIP
                    </span>
                  ) : (
                    o.icons.map((ic, idx) => (
                      <ItemIcon
                        key={`${o.id}-${ic.itemId}-${idx}`}
                        id={ic.itemId}
                        size={32}
                        alt={o.name}
                      />
                    ))
                  )}
                </div>
                <div className="mt-3 min-w-0">
                  <div className="truncate font-medium">{o.name}</div>
                  <div className="mt-1 text-sm font-semibold text-brand">
                    {o.points} {pointsUnit}
                    {o.days > 0 ? (
                      <span className="ml-2 text-xs font-normal text-muted">
                        {o.days}d
                      </span>
                    ) : null}
                  </div>
                  <div
                    className="mt-2 line-clamp-3 text-xs text-muted"
                    dangerouslySetInnerHTML={{ __html: o.descriptionHtml }}
                  />
                </div>
                <span className="mt-3 text-xs text-brand">{t.shop.viewBuy}</span>
              </button>
            ))}
          </div>
        )}

        {loggedIn && (data?.stats || (data?.history?.length ?? 0) > 0) && (
          <section className="mt-12">
            <h2 className="text-xl font-semibold tracking-tight">{t.shop.historyTitle}</h2>
            {/* BEGIN CHANGE: player shop stats strip */}
            {data?.stats && (
              <div className="mt-3 flex flex-wrap gap-3 text-sm text-muted">
                <span>
                  {t.shop.statsWaiting}:{" "}
                  <span className="font-medium text-foreground">{data.stats.waiting}</span>
                </span>
                <span>
                  {t.shop.statsSpent30d}:{" "}
                  <span className="font-medium text-brand">
                    {data.stats.spent30d} {pointsUnit}
                  </span>
                </span>
                <span>
                  {t.shop.statsLastBuy}:{" "}
                  <span className="font-medium text-foreground">
                    {data.stats.lastBuy > 0 ? formatDate(data.stats.lastBuy) : "-"}
                  </span>
                </span>
              </div>
            )}
            {/* END CHANGE */}
            {(data?.history?.length ?? 0) > 0 && (
              <>
                {/* BEGIN CHANGE: history mobile cards + desktop scroll */}
                <div className="mt-4 space-y-3 md:hidden">
                  {(data?.history ?? []).map((h) => (
                    <div
                      key={`m-${h.catalog || catalog}-${h.kind}-${h.id}`}
                      className="rounded-xl border border-border bg-panel p-4 text-sm"
                    >
                      <div className="flex flex-wrap items-start justify-between gap-2">
                        <ShopHistoryWhat
                          kind={h.kind}
                          itemName={h.itemName}
                          days={h.days}
                          premiumDaysLabel={t.shop.premiumDays}
                          items={h.items}
                          serialItem={h.serialItem}
                        />
                        <div className="text-brand">
                          {h.price}{" "}
                          {(h.catalog || catalog) === "guild" ? t.shop.unitGP : t.shop.unitPP}
                        </div>
                      </div>
                      <div className="mt-2 text-muted">{formatDate(h.started)}</div>
                      <div className="mt-1 text-muted">
                        {(h.catalog || catalog) === "guild" ? t.shop.tabGuild : t.shop.tabDonate}
                        {" - "}
                        {h.toName}
                      </div>
                      <div className="mt-1 text-muted">
                        {h.state === "wait" ? t.shop.stateWait : t.shop.stateDone}
                      </div>
                      {h.serialItem ? (
                        <div className="mt-2">
                          <div className="text-xs text-muted">{t.shop.colSerial}</div>
                          <ShopHistorySerials serialItem={h.serialItem} className="mt-1" />
                        </div>
                      ) : null}
                    </div>
                  ))}
                </div>
                <div className="mt-4 hidden overflow-x-auto rounded-xl border border-border bg-panel md:block">
                  <table className="w-full min-w-[720px] text-sm">
                    <thead>
                      <tr className="border-b border-border text-left text-muted">
                        <th className="px-4 py-3 font-medium">{t.shop.colWhen}</th>
                        <th className="px-4 py-3 font-medium">{t.auth.histCatalog}</th>
                        <th className="px-4 py-3 font-medium">{t.shop.colTo}</th>
                        <th className="px-4 py-3 font-medium">{t.shop.colWhat}</th>
                        <th className="px-4 py-3 font-medium">{t.shop.colPrice}</th>
                        <th className="px-4 py-3 font-medium">{t.shop.colState}</th>
                        <th className="px-4 py-3 font-medium">{t.shop.colSerial}</th>
                      </tr>
                    </thead>
                    <tbody>
                      {(data?.history ?? []).map((h) => (
                        <tr
                          key={`${h.catalog || catalog}-${h.kind}-${h.id}`}
                          className="border-b border-border/50 last:border-0"
                        >
                          <td className="px-4 py-3 text-muted">{formatDate(h.started)}</td>
                          <td className="px-4 py-3 text-muted">
                            {(h.catalog || catalog) === "guild" ? t.shop.tabGuild : t.shop.tabDonate}
                          </td>
                          <td className="px-4 py-3">{h.toName}</td>
                          <td className="px-4 py-3">
                            <ShopHistoryWhat
                              kind={h.kind}
                              itemName={h.itemName}
                              days={h.days}
                              premiumDaysLabel={t.shop.premiumDays}
                              items={h.items}
                              serialItem={h.serialItem}
                            />
                          </td>
                          <td className="px-4 py-3 text-brand">
                            {h.price}{" "}
                            {(h.catalog || catalog) === "guild" ? t.shop.unitGP : t.shop.unitPP}
                          </td>
                          <td className="px-4 py-3 text-muted">
                            {h.state === "wait" ? t.shop.stateWait : t.shop.stateDone}
                          </td>
                          <td className="px-4 py-3 align-top">
                            <ShopHistorySerials serialItem={h.serialItem} />
                          </td>
                        </tr>
                      ))}
                    </tbody>
                  </table>
                </div>
                {/* END CHANGE */}
              </>
            )}
          </section>
        )}
      </main>

      {selected && (
        <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4">
          <div className="max-h-[90vh] w-full max-w-lg overflow-y-auto rounded-xl border border-border bg-panel p-5 shadow-xl">
            <div className="flex items-start justify-between gap-3">
              <h2 className="text-lg font-semibold">{selected.name}</h2>
              <button
                type="button"
                className="text-sm text-muted hover:text-foreground"
                onClick={closeBuy}
              >
                {t.shop.close}
              </button>
            </div>

            {/* BEGIN CHANGE: sempre mostrar itens do set/armas no modal */}
            <div className="mt-3 flex flex-wrap gap-2">
              {selected.offerType === "pacc" ? (
                <span className="grid h-12 w-12 place-items-center rounded bg-background text-xs">
                  VIP
                </span>
              ) : (
                selected.icons.map((ic, idx) => (
                  <ItemIcon
                    key={`sel-${ic.itemId}-${idx}`}
                    id={ic.itemId}
                    size={40}
                    alt={selected.name}
                  />
                ))
              )}
            </div>
            {/* END CHANGE */}

            <p className="mt-3 text-sm font-semibold text-brand">
              {qtyEnabled
                ? `${totalPrice} ${pointsUnit}`
                : `${selected.points} ${pointsUnit}`}
              {qtyEnabled && buyQty > 1 ? (
                <span className="ml-2 text-xs font-normal text-muted">
                  ({selected.points} x {buyQty})
                </span>
              ) : null}
            </p>
            <div
              className="mt-3 text-sm text-muted"
              dangerouslySetInnerHTML={{ __html: selected.descriptionHtml }}
            />

            {/* BEGIN CHANGE: quantity selector when catalog allows */}
            {qtyEnabled && loggedIn && !confirmOpen && (
              <label className="mt-4 block text-sm">
                <span className="text-muted">{t.shop.quantityLabel}</span>
                <input
                  type="number"
                  min={1}
                  max={qtyMax}
                  className="mt-1 w-full rounded border border-border bg-background px-3 py-2"
                  value={buyQty}
                  onChange={(e) => {
                    const n = Number(e.target.value) || 1;
                    setBuyQty(Math.min(qtyMax, Math.max(1, n)));
                  }}
                />
                <span className="mt-1 block text-xs text-muted">
                  {t.shop.quantityHint
                    .replace("{max}", String(qtyMax))
                    .replace("{unit}", pointsUnit)
                    .replace("{total}", String(totalPrice))}
                </span>
              </label>
            )}
            {/* END CHANGE */}

            {/* BEGIN CHANGE: preview do set fixo antes da escolha de arma */}
            {needsChoice &&
              loggedIn &&
              !confirmOpen &&
              chooserGroups.length > 0 &&
              bundleStep < chooserGroups.length &&
              bundleGroups.some(isFixedGroup) && (
                <div className="mt-4 rounded-lg border border-border bg-background p-3">
                  <p className="text-sm font-medium text-muted">
                    {t.shop.bundleIncludedSet}
                  </p>
                  <ul className="mt-2 space-y-2">
                    {bundleGroups.filter(isFixedGroup).map((g) => {
                      const op = g.options[0];
                      if (!op) return null;
                      return (
                        <li key={g.id}>
                          <span className="text-sm">
                            <span className="text-muted">{g.label}: </span>
                            {op.label}
                          </span>
                          <div className="mt-1 flex flex-wrap gap-1">
                            {op.items.map((it, idx) => (
                              <ItemIcon
                                key={`fixed-${g.id}-${it.itemId}-${idx}`}
                                id={it.itemId}
                                size={32}
                                alt={op.label}
                              />
                            ))}
                          </div>
                        </li>
                      );
                    })}
                  </ul>
                </div>
              )}
            {/* END CHANGE */}

            {/* BEGIN CHANGE: wizard bundle no modal do card */}
            {needsChoice &&
              loggedIn &&
              !confirmOpen &&
              chooserGroups.length > 0 &&
              bundleStep < chooserGroups.length && (
                <div className="mt-5 space-y-3">
                  <p className="text-sm font-medium">
                    {t.shop.bundleStep
                      .replace("{n}", String(bundleStep + 1))
                      .replace("{label}", chooserGroups[bundleStep].label)}
                  </p>
                  <div className="grid gap-2">
                    {chooserGroups[bundleStep].options.map((op) => {
                      const picked = (
                        bundlePicks[chooserGroups[bundleStep].id] ?? []
                      ).includes(op.id);
                      return (
                        <button
                          key={op.id}
                          type="button"
                          onClick={() =>
                            toggleBundleOption(chooserGroups[bundleStep], op.id)
                          }
                          className={`rounded-lg border p-3 text-left transition-colors ${
                            picked
                              ? "border-brand/60 bg-brand/15"
                              : "border-border hover:border-brand/30"
                          }`}
                        >
                          <div className="flex flex-wrap items-center gap-2">
                            {op.items.map((it, idx) => (
                              <ItemIcon
                                key={`${op.id}-${it.itemId}-${idx}`}
                                id={it.itemId}
                                size={32}
                                alt={op.label}
                              />
                            ))}
                          </div>
                          <div className="mt-2 text-sm font-medium">{op.label}</div>
                        </button>
                      );
                    })}
                  </div>
                  {err && <p className="text-sm text-red-400">{err}</p>}
                  <div className="flex flex-wrap gap-2">
                    {bundleStep > 0 && (
                      <button
                        type="button"
                        className="rounded border border-border px-4 py-2 text-sm"
                        onClick={() => {
                          setBundleStep((s) => Math.max(0, s - 1));
                          setErr("");
                        }}
                      >
                        {t.shop.back}
                      </button>
                    )}
                    <button
                      type="button"
                      disabled={!currentBundleGroupValid()}
                      className="rounded bg-brand px-4 py-2 text-sm font-medium text-white disabled:opacity-50"
                      onClick={() => {
                        if (!currentBundleGroupValid()) {
                          setErr(t.shop.bundlePickRequired);
                          return;
                        }
                        setErr("");
                        setBundleStep((s) => s + 1);
                      }}
                    >
                      {t.shop.bundleContinue}
                    </button>
                  </div>
                </div>
              )}
            {/* END CHANGE */}

            {!loggedIn ? (
              <p className="mt-6 text-sm text-muted">
                {t.shop.needLogin}{" "}
                <Link href="/login" className="text-brand hover:underline">
                  {t.nav.items.login}
                </Link>
              </p>
            ) : needsChoice &&
              !confirmOpen &&
              chooserGroups.length > 0 &&
              bundleStep < chooserGroups.length ? null : !confirmOpen ? (
              <form onSubmit={onSubmitBuy} className="mt-6 space-y-3">
                {needsChoice && bundleGroups.length > 0 && (
                  <div className="rounded-lg border border-border bg-background p-3 text-sm">
                    <p className="font-medium">{t.shop.bundleSummary}</p>
                    <ul className="mt-2 space-y-2">
                      {bundleGroups.map((g) => {
                        const ids = bundlePicks[g.id] ?? [];
                        const opts = g.options.filter((o) => ids.includes(o.id));
                        return (
                          <li key={g.id}>
                            <span className="text-muted">{g.label}: </span>
                            {opts.length === 0
                              ? "-"
                              : opts.map((o) => o.label).join(", ")}
                            <div className="mt-1 flex flex-wrap gap-1">
                              {opts.flatMap((o) =>
                                o.items.map((it, idx) => (
                                  <ItemIcon
                                    key={`sum-${g.id}-${o.id}-${it.itemId}-${idx}`}
                                    id={it.itemId}
                                    size={24}
                                    alt={o.label}
                                  />
                                ))
                              )}
                            </div>
                          </li>
                        );
                      })}
                    </ul>
                    <button
                      type="button"
                      className="mt-2 text-xs text-brand hover:underline"
                      onClick={() => {
                        setBundleStep(0);
                        setConfirmOpen(false);
                      }}
                    >
                      {t.shop.back}
                    </button>
                  </div>
                )}
                {/* BEGIN CHANGE: marcar meus chars vs outro personagem */}
                <div className="flex flex-wrap gap-2 text-sm">
                  <button
                    type="button"
                    disabled={(data?.characters?.length ?? 0) === 0}
                    onClick={() => {
                      setDestMode("own");
                      const chars = data?.characters ?? [];
                      if (chars.length > 0) setPlayerName(chars[0].name);
                    }}
                    className={`rounded-lg border px-3 py-1.5 ${
                      destMode === "own"
                        ? "border-brand/50 bg-brand/15 font-medium"
                        : "border-border text-muted"
                    } disabled:opacity-40`}
                  >
                    {t.shop.destOwn}
                  </button>
                  <button
                    type="button"
                    onClick={() => {
                      setDestMode("other");
                      setPlayerName("");
                    }}
                    className={`rounded-lg border px-3 py-1.5 ${
                      destMode === "other"
                        ? "border-brand/50 bg-brand/15 font-medium"
                        : "border-border text-muted"
                    }`}
                  >
                    {t.shop.destOther}
                  </button>
                </div>

                {destMode === "own" ? (
                  <label className="block text-sm">
                    <span className="text-muted">{t.shop.yourCharacters}</span>
                    <select
                      className="mt-1 w-full rounded border border-border bg-background px-3 py-2"
                      value={playerName}
                      onChange={(e) => setPlayerName(e.target.value)}
                      required
                    >
                      {(data?.characters ?? []).map((c) => (
                        <option key={c.name} value={c.name}>
                          {c.name} - {c.vocation} {c.level}
                          {c.online ? ` (${t.shop.destOnline})` : ` (${t.shop.destOffline})`}
                        </option>
                      ))}
                    </select>
                    {/* BEGIN CHANGE: online badge (warn only) */}
                    {(() => {
                      const cur = (data?.characters ?? []).find((c) => c.name === playerName);
                      if (!cur) return null;
                      return (
                        <span
                          className={`mt-1 inline-flex rounded px-2 py-0.5 text-xs ${
                            cur.online
                              ? "bg-emerald-500/15 text-emerald-300"
                              : "bg-amber-500/15 text-amber-200"
                          }`}
                        >
                          {cur.online ? t.shop.destOnline : t.shop.destOfflineHint}
                        </span>
                      );
                    })()}
                    {/* END CHANGE */}
                  </label>
                ) : (
                  <label className="block text-sm">
                    <span className="text-muted">{t.shop.playerName}</span>
                    <input
                      className="mt-1 w-full rounded border border-border bg-background px-3 py-2"
                      value={playerName}
                      onChange={(e) => setPlayerName(e.target.value)}
                      placeholder={t.shop.playerPlaceholder}
                      required
                    />
                    <span className="mt-1 block text-xs text-muted">{t.shop.giftHint}</span>
                    {/* BEGIN CHANGE: gift online soft warn */}
                    <span className="mt-1 block text-xs text-amber-200/90">
                      {t.shop.destOfflineHint}
                    </span>
                    {/* END CHANGE */}
                  </label>
                )}
                {/* END CHANGE */}
                {err && <p className="text-sm text-red-400">{err}</p>}
                <button
                  type="submit"
                  disabled={busy || !playerName.trim() || !bundleChoicesValid}
                  className="rounded bg-brand px-4 py-2 text-sm font-medium text-white disabled:opacity-50"
                >
                  {t.shop.continueConfirm}
                </button>
              </form>
            ) : (
              <div className="mt-6 space-y-3">
                <p className="text-sm">
                  {t.shop.confirmText
                    .replace("{name}", selected.name)
                    .replace("{price}", String(totalPrice))
                    .replace("{unit}", pointsUnit)
                    .replace("{player}", playerName)}
                  {qtyEnabled && buyQty > 1
                    ? ` (${buyQty}x)`
                    : ""}
                </p>
                {/* BEGIN CHANGE: confirm online hint */}
                {(() => {
                  const cur = (data?.characters ?? []).find((c) => c.name === playerName);
                  if (destMode === "own" && cur?.online) return null;
                  return (
                    <p className="text-xs text-amber-200/90">{t.shop.destOfflineHint}</p>
                  );
                })()}
                {/* END CHANGE */}
                {err && <p className="text-sm text-red-400">{err}</p>}
                <div className="flex flex-wrap gap-2">
                  <button
                    type="button"
                    disabled={busy}
                    onClick={() => void doBuy()}
                    className="rounded bg-brand px-4 py-2 text-sm font-medium text-white disabled:opacity-50"
                  >
                    {t.shop.confirmBuy}
                  </button>
                  <button
                    type="button"
                    disabled={busy}
                    onClick={() => setConfirmOpen(false)}
                    className="rounded border border-border px-4 py-2 text-sm"
                  >
                    {t.shop.back}
                  </button>
                </div>
              </div>
            )}
          </div>
        </div>
      )}

      <Footer />
    </div>
  );
}
// END CHANGE
