// BEGIN CHANGE: pagina Character - paridade com characters.php (set, quests, dodge)
"use client";

import { useEffect, useState, FormEvent, type ReactNode } from "react";
import Link from "next/link";
import { useI18n } from "@/i18n/LanguageProvider";
import { Navbar } from "@/components/Navbar";
import { Footer } from "@/components/Footer";
import { Outfit } from "@/components/Outfit";
import { ItemIcon } from "@/components/ItemIcon";
import { CollapsiblePanel } from "@/components/CollapsiblePanel";
import {
  apiUrl,
  equipmentEmptyBgUrl,
  equipmentPanelBgUrl,
  equipmentSlotUrl,
  patenteUrl,
  type Look,
} from "@/lib/api";

type EqSlot = { slot: number; itemId: number | null };
type Quest = { name: string; done: boolean };
type Killer =
  | {
      type: "monster";
      monster: string;
      count: number;
      look: Look | null;
      itemId: number | null;
    }
  | {
      type: "player";
      player: string;
      count: number;
      deleted?: boolean;
      look: Look | null;
    }
  | {
      type: "summon";
      monster: string;
      player: string;
      count: number;
      monsterLook: Look | null;
      monsterItem: number | null;
      playerLook: Look | null;
    };
type Death = { date: number; level: number; killers: Killer[] };
// BEGIN CHANGE: progresso de tasks e addons do personagem
type TaskMission = {
  id: number;
  name: string;
  requiredLevel?: number;
  status: "not_started" | "in_progress" | "ready_to_deliver" | "expired";
  kills: number;
  requiredKills: number;
  remaining: number;
  expiresAt?: number;
  monsters: string[];
};
type TaskProgress = {
  points: number;
  rank: string;
  current: TaskMission | null;
  daily: TaskMission | null;
  allCompleted: boolean;
};
type PlayerAddon = {
  outfitId: number;
  name: string;
  level: 1 | 2 | 3;
  lookType: number;
};
// END CHANGE

type Char = {
  name: string;
  oldName: string | null;
  level: number;
  reset: number;
  vocation: string;
  experience: number;
  magic: number;
  sex: string;
  online: boolean;
  // BEGIN CHANGE: Premium Account da conta
  isPremium: boolean;
  premiumDays: number;
  // END CHANGE
  lastlogin: number;
  created: number;
  position: string | null;
  healthMax: number;
  manaMax: number;
  dodge: number;
  critical: number;
  mining: number;
  residence: string | null;
  balance: number;
  armyLevel: number;
  armyRank: string | null;
  frags: number;
  marriedTo: string | null;
  comment: string | null;
  guild: string | null;
  guildId: number | null;
  guildRank: string | null;
  skills: { name: string; value: number }[];
  equipment: EqSlot[];
  quests: Quest[];
  taskProgress: TaskProgress;
  addons: PlayerAddon[];
  deaths: Death[];
  look: Look;
  resetBonus?: {
    rr: number;
    damagePercent: number;
    hpmpPercent: number;
    damageMultiplier: number;
  };
};

type State = "idle" | "loading" | "ok" | "notfound" | "error";

export default function CharacterPage() {
  const { t } = useI18n();
  const [input, setInput] = useState("");
  const [data, setData] = useState<Char | null>(null);
  const [state, setState] = useState<State>("idle");
  // BEGIN CHANGE: modo embed reutiliza exatamente o resultado publico dentro do Admin
  const [embedded, setEmbedded] = useState(false);
  // END CHANGE

  function load(name: string) {
    if (!name) return;
    setState("loading");
    fetch(apiUrl(`character.php?name=${encodeURIComponent(name)}`))
      .then((r) => {
        if (r.status === 404) {
          setState("notfound");
          return null;
        }
        if (!r.ok) throw new Error("http " + r.status);
        return r.json();
      })
      .then((json) => {
        if (json && json.data) {
          setData(json.data);
          setState("ok");
        }
      })
      .catch(() => setState("error"));
  }

  // Soft-nav na mesma rota (/character/?name=) nao remonta a pagina;
  // reage a mudancas da query (Link, pushState, voltar/avancar).
  function syncFromUrl() {
    const params = new URLSearchParams(window.location.search);
    const name = params.get("name") ?? "";
    // BEGIN CHANGE: sem Navbar, busca e Footer quando incorporado no Inspector
    setEmbedded(params.get("embed") === "1");
    // END CHANGE
    setInput(name);
    if (name) {
      load(name);
      window.scrollTo({ top: 0, behavior: "smooth" });
    } else {
      setData(null);
      setState("idle");
    }
  }

  useEffect(() => {
    syncFromUrl();
    const onPop = () => syncFromUrl();
    window.addEventListener("popstate", onPop);
    const push = history.pushState.bind(history);
    const replace = history.replaceState.bind(history);
    history.pushState = (...args: Parameters<History["pushState"]>) => {
      push(...args);
      syncFromUrl();
    };
    history.replaceState = (...args: Parameters<History["replaceState"]>) => {
      replace(...args);
      syncFromUrl();
    };
    return () => {
      window.removeEventListener("popstate", onPop);
      history.pushState = push;
      history.replaceState = replace;
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  function onSubmit(e: FormEvent) {
    e.preventDefault();
    const name = input.trim();
    if (!name) return;
    window.history.replaceState(null, "", `/character/?name=${encodeURIComponent(name)}`);
    // syncFromUrl ja cobre via patch de replaceState
  }

  const fmtDate = (epoch: number) =>
    epoch > 0 ? new Date(epoch * 1000).toLocaleString() : t.character.never;

  return (
    <div className={embedded ? "min-h-screen bg-background" : "flex min-h-screen flex-col"}>
      {!embedded && <Navbar />}
      <main className={embedded ? "w-full p-3 sm:p-4" : "mx-auto w-full max-w-4xl flex-1 px-6 py-14"}>
        {!embedded && (
          <>
            <h1 className="text-3xl font-semibold tracking-tight">{t.character.title}</h1>

            <form onSubmit={onSubmit} className="mt-6 flex gap-2">
              <input
                value={input}
                onChange={(e) => setInput(e.target.value)}
                placeholder={t.character.searchPlaceholder}
                className="flex-1 rounded-lg border border-border bg-panel px-4 py-2 text-sm outline-none focus:border-brand/60"
              />
              <button
                type="submit"
                className="rounded-lg bg-brand px-5 py-2 text-sm font-medium text-background transition-opacity hover:opacity-90"
              >
                {t.character.search}
              </button>
            </form>
          </>
        )}

        <div className={embedded ? "" : "mt-8"}>
          {state === "idle" && <p className="text-muted">{t.character.prompt}</p>}
          {state === "loading" && <p className="text-muted">{t.common.loading}</p>}
          {state === "error" && <p className="text-muted">{t.common.error}</p>}
          {state === "notfound" && <p className="text-muted">{t.character.notFound}</p>}
          {state === "ok" && data && (
            <div className="space-y-6">
              <div className="rounded-xl border border-border bg-panel p-6">
                {/* BEGIN CHANGE: outfit maior + equipamento maior e centralizado */}
                <div className="flex flex-col items-center gap-5">
                  <div className="flex flex-col items-center gap-3 sm:flex-row sm:items-center sm:gap-5">
                    <Outfit look={data.look} size="profile" alt={data.name} />
                    <div className="text-center sm:text-left">
                      <h2 className="text-xl font-semibold">{data.name}</h2>
                      <span
                        className={`mt-1 inline-block rounded-full px-3 py-1 text-xs ${
                          data.online
                            ? "bg-brand/15 text-brand"
                            : "bg-background text-muted"
                        }`}
                      >
                        {data.online ? t.character.online : t.character.offline}
                      </span>
                    </div>
                  </div>
                  <EquipmentGrid slots={data.equipment} title={t.character.equipment} />
                </div>
                {/* END CHANGE */}

                <dl className="mt-6 grid grid-cols-1 gap-x-8 gap-y-3 text-sm sm:grid-cols-2">
                  {/* BEGIN CHANGE: status Premium Account (+ dias restantes) */}
                  <Row
                    k={t.character.accountStatus}
                    v={
                      <span className={data.isPremium ? "font-semibold text-emerald-400" : ""}>
                        {data.isPremium
                          ? `${t.character.premiumAccount} (${data.premiumDays} ${t.character.premiumDays})`
                          : t.character.freeAccount}
                      </span>
                    }
                  />
                  {/* END CHANGE */}
                  {data.position && <Row k={t.character.position} v={data.position} />}
                  {data.oldName && <Row k={t.character.oldName} v={data.oldName} />}
                  <Row
                    k={t.character.sex}
                    v={data.sex === "male" ? t.character.male : t.character.female}
                  />
                  <div className="flex justify-between gap-4 border-b border-border/40 pb-2">
                    <span className="shrink-0 text-muted">{t.character.marital}</span>
                    <span className="text-right font-medium">
                      {data.marriedTo ? (
                        <>
                          {t.character.marriedTo}{" "}
                          <Link
                            href={`/character/?name=${encodeURIComponent(data.marriedTo)}`}
                            className="text-brand hover:underline"
                          >
                            {data.marriedTo}
                          </Link>
                        </>
                      ) : (
                        t.character.single
                      )}
                    </span>
                  </div>
                  <Row k={t.character.vocation} v={data.vocation} />
                  <Row k={t.character.level} v={String(data.level)} />
                  <Row k={t.character.resets} v={String(data.reset)} />
                  {data.resetBonus && (
                    <div className="sm:col-span-2 rounded-lg border border-border/70 bg-background/40 px-4 py-3">
                      <div className="flex flex-wrap items-baseline justify-between gap-2">
                        <span className="text-sm font-semibold">{t.character.resetPower}</span>
                        <Link href="/server-info" className="text-xs text-brand hover:underline">
                          {t.character.resetPowerTable}
                        </Link>
                      </div>
                      <p className="mt-1 text-xs text-muted">{t.character.resetPowerHint}</p>
                      <dl className="mt-3 grid grid-cols-1 gap-2 text-sm sm:grid-cols-3">
                        <div className="rounded-md border border-border/50 px-3 py-2">
                          <dt className="text-xs text-muted">{t.character.resetDamage}</dt>
                          <dd className="mt-0.5 font-semibold text-brand">
                            +{data.resetBonus.damagePercent}%
                          </dd>
                        </div>
                        <div className="rounded-md border border-border/50 px-3 py-2">
                          <dt className="text-xs text-muted">{t.character.resetHpMp}</dt>
                          <dd className="mt-0.5 font-semibold text-brand">
                            +{data.resetBonus.hpmpPercent}%
                          </dd>
                        </div>
                        <div className="rounded-md border border-border/50 px-3 py-2">
                          <dt className="text-xs text-muted">{t.character.resetMultiplier}</dt>
                          <dd className="mt-0.5 font-semibold">
                            {data.resetBonus.damageMultiplier.toFixed(2)}x
                          </dd>
                        </div>
                      </dl>
                    </div>
                  )}
                  <Row k={t.character.healthMax} v={String(data.healthMax)} />
                  <Row k={t.character.manaMax} v={String(data.manaMax)} />
                  <Row k={t.character.dodge} v={`Level ${data.dodge}`} />
                  <Row k={t.character.critical} v={`Level ${data.critical}`} />
                  <Row k={t.character.mining} v={`Level ${data.mining}`} />
                  <Row k={t.character.magic} v={String(data.magic)} />
                  <Row k={t.character.experience} v={data.experience.toLocaleString()} />
                  {data.residence && <Row k={t.character.residence} v={data.residence} />}
                  <Row
                    k={t.character.balance}
                    v={`${data.balance.toLocaleString()} ${t.character.goldCoins}`}
                  />
                  {data.armyLevel > 0 && (
                    <div className="flex justify-between gap-4 border-b border-border/40 pb-2">
                      <span className="shrink-0 text-muted">{t.character.army}</span>
                      <span className="inline-flex items-center gap-2 text-right font-medium">
                        {/* eslint-disable-next-line @next/next/no-img-element */}
                        <img
                          src={patenteUrl(data.armyLevel)}
                          alt=""
                          width={22}
                          height={22}
                          className="object-contain"
                        />
                        {data.armyRank ?? `Level ${data.armyLevel}`}
                      </span>
                    </div>
                  )}
                  {data.frags > 0 && <Row k={t.character.frags} v={String(data.frags)} />}
                  <div className="flex justify-between gap-4 border-b border-border/40 pb-2">
                    <span className="shrink-0 text-muted">{t.character.guild}</span>
                    <span className="text-right font-medium">
                      {data.guild ? (
                        <>
                          {data.guildRank ? `${data.guildRank} of ` : ""}
                          {data.guildId ? (
                            <Link
                              href={`/guild/?id=${data.guildId}`}
                              className="text-brand hover:underline"
                            >
                              {data.guild}
                            </Link>
                          ) : (
                            data.guild
                          )}
                        </>
                      ) : (
                        t.character.noGuild
                      )}
                    </span>
                  </div>
                  <Row k={t.character.lastLogin} v={fmtDate(data.lastlogin)} />
                  {data.created > 0 && (
                    <Row k={t.character.created} v={fmtDate(data.created)} />
                  )}
                </dl>

                {data.comment && (
                  <div className="mt-4 border-t border-border/40 pt-4 text-sm">
                    <div className="text-muted">{t.character.comment}</div>
                    <p className="mt-1 whitespace-pre-wrap">{data.comment}</p>
                  </div>
                )}
              </div>

              {/* BEGIN CHANGE: task atual, progresso, faltantes e nivel/rank */}
              <TaskProgressCard progress={data.taskProgress} />
              {/* END CHANGE */}

              {/* BEGIN CHANGE: collapsible secondary sections */}
              <Section id="char-addons" title={t.character.addons} defaultOpen={false}>
                {data.addons.length === 0 ? (
                  <p className="text-sm text-muted">{t.character.noAddons}</p>
                ) : (
                  <div className="overflow-x-auto rounded-lg border border-border">
                    <table className="w-full text-left text-sm">
                      <thead className="bg-background text-muted">
                        <tr>
                          <th className="px-3 py-2">{t.character.addonOutfit}</th>
                          <th className="px-3 py-2">{t.character.addonLevel}</th>
                          <th className="px-3 py-2">{t.character.addonOwned}</th>
                        </tr>
                      </thead>
                      <tbody>
                        {data.addons.map((addon) => (
                          <tr key={addon.outfitId} className="border-t border-border/50">
                            <td className="px-3 py-2 font-medium">{addon.name}</td>
                            <td className="px-3 py-2 tabular-nums">{addon.level}</td>
                            <td className="px-3 py-2 text-muted">
                              {addon.level === 1
                                ? t.character.addonFirst
                                : addon.level === 2
                                  ? t.character.addonSecond
                                  : t.character.addonFull}
                            </td>
                          </tr>
                        ))}
                      </tbody>
                    </table>
                  </div>
                )}
              </Section>
              {/* END CHANGE */}

              {data.skills.length > 0 && (
                <Section id="char-skills" title={t.character.skills}>
                  <div className="grid grid-cols-2 gap-x-8 gap-y-3 text-sm sm:grid-cols-3">
                    {data.skills.map((s) => (
                      <div key={s.name} className="flex justify-between">
                        <span className="text-muted">{s.name}</span>
                        <span className="font-medium">{s.value}</span>
                      </div>
                    ))}
                  </div>
                </Section>
              )}

              {data.quests.length > 0 && (
                <Section id="char-quests" title={t.character.quests} defaultOpen={false}>
                  <ul className="divide-y divide-border/40 text-sm">
                    {data.quests.map((q) => (
                      <li key={q.name} className="flex items-center justify-between py-2">
                        <span>{q.name}</span>
                        {/* eslint-disable-next-line @next/next/no-img-element */}
                        <img
                          src={
                            q.done
                              ? "https://ot.whiteantidote.com/images/true.png"
                              : "https://ot.whiteantidote.com/images/false.png"
                          }
                          alt={q.done ? "yes" : "no"}
                          width={16}
                          height={16}
                        />
                      </li>
                    ))}
                  </ul>
                </Section>
              )}

              {data.deaths.length > 0 && (
                <Section id="char-deaths" title={t.character.deaths} defaultOpen={false}>
                  <ul className="space-y-4 text-sm">
                    {data.deaths.map((d, i) => (
                      <li
                        key={`${d.date}-${i}`}
                        className="border-b border-border/40 pb-4 last:border-0"
                      >
                        <div className="flex flex-wrap gap-x-4 gap-y-1 text-muted">
                          <span>{fmtDate(d.date)}</span>
                          <span>
                            {t.character.levelLabel} {d.level}
                          </span>
                        </div>
                        <div className="mt-2 flex flex-wrap items-center gap-x-1 gap-y-2">
                          <span className="text-muted">{t.character.killedBy}:</span>
                          {d.killers.length === 0 ? (
                            <span>-</span>
                          ) : (
                            d.killers.map((k, ki) => (
                              <span
                                key={ki}
                                className="inline-flex flex-wrap items-center gap-1"
                              >
                                {ki > 0 && (
                                  <span className="text-muted">
                                    {ki === d.killers.length - 1 ? " and " : ", "}
                                  </span>
                                )}
                                <KillerChip killer={k} />
                              </span>
                            ))
                          )}
                        </div>
                      </li>
                    ))}
                  </ul>
                </Section>
              )}
            </div>
          )}
        </div>
      </main>
      {!embedded && <Footer />}
    </div>
  );
}

// BEGIN CHANGE: card completo do Task System
function TaskProgressCard({ progress }: { progress: TaskProgress }) {
  const { t } = useI18n();
  const statusLabel = (status: TaskMission["status"]) => {
    if (status === "not_started") return t.character.taskNotStarted;
    if (status === "ready_to_deliver") return t.character.taskReady;
    if (status === "expired") return t.character.taskExpired;
    return t.character.taskInProgress;
  };

  return (
    <Section id="char-tasks" title={t.character.taskTitle}>
      <div className="mb-4 grid gap-3 sm:grid-cols-2">
        <div className="rounded-lg border border-border/60 bg-background/40 px-4 py-3">
          <div className="text-xs text-muted">{t.character.taskLevel}</div>
          <div className="mt-1 font-semibold text-brand">{progress.rank}</div>
        </div>
        <div className="rounded-lg border border-border/60 bg-background/40 px-4 py-3">
          <div className="text-xs text-muted">{t.character.taskPoints}</div>
          <div className="mt-1 font-semibold">{progress.points}</div>
        </div>
      </div>

      {progress.allCompleted ? (
        <p className="text-sm text-brand">{t.character.taskAllCompleted}</p>
      ) : progress.current ? (
        <TaskMissionDetails
          mission={progress.current}
          title={t.character.taskCurrent}
          statusLabel={statusLabel(progress.current.status)}
        />
      ) : (
        <p className="text-sm text-muted">{t.character.taskNone}</p>
      )}

      {progress.daily && (
        <div className="mt-4 border-t border-border/50 pt-4">
          <TaskMissionDetails
            mission={progress.daily}
            title={t.character.taskDaily}
            statusLabel={statusLabel(progress.daily.status)}
          />
        </div>
      )}
    </Section>
  );
}

function TaskMissionDetails({
  mission,
  title,
  statusLabel,
}: {
  mission: TaskMission;
  title: string;
  statusLabel: string;
}) {
  const { t } = useI18n();
  const pct =
    mission.requiredKills > 0
      ? Math.min(100, Math.round((mission.kills / mission.requiredKills) * 100))
      : 0;
  return (
    <div>
      <div className="flex flex-wrap items-start justify-between gap-2">
        <div>
          <div className="text-xs text-muted">{title}</div>
          <h4 className="font-semibold">{mission.name}</h4>
        </div>
        <span className="rounded-full border border-brand/30 bg-brand/10 px-2.5 py-1 text-xs text-brand">
          {statusLabel}
        </span>
      </div>
      <div className="mt-3 h-2 overflow-hidden rounded-full bg-background">
        <div className="h-full rounded-full bg-brand" style={{ width: `${pct}%` }} />
      </div>
      <div className="mt-2 grid gap-2 text-sm sm:grid-cols-3">
        <div>
          <span className="text-muted">{t.character.taskKilled}: </span>
          <strong>{mission.kills}</strong>
        </div>
        <div>
          <span className="text-muted">{t.character.taskRequired}: </span>
          <strong>{mission.requiredKills}</strong>
        </div>
        <div>
          <span className="text-muted">{t.character.taskRemaining}: </span>
          <strong>{mission.remaining}</strong>
        </div>
      </div>
      {mission.requiredLevel != null && (
        <p className="mt-2 text-xs text-muted">
          {t.character.taskRequiredLevel}: {mission.requiredLevel}
        </p>
      )}
      {mission.expiresAt != null && mission.expiresAt > 0 && (
        <p className="mt-2 text-xs text-muted">
          {t.character.taskDeadline}: {new Date(mission.expiresAt * 1000).toLocaleString()}
        </p>
      )}
      {mission.monsters.length > 0 && (
        <p className="mt-2 text-xs text-muted">
          {t.character.taskMonsters}: {mission.monsters.join(", ")}
        </p>
      )}
    </div>
  );
}
// END CHANGE

function Section({
  id,
  title,
  children,
  defaultOpen = true,
}: {
  id: string;
  title: string;
  children: ReactNode;
  defaultOpen?: boolean;
}) {
  return (
    <CollapsiblePanel id={id} title={title} defaultOpen={defaultOpen}>
      {children}
    </CollapsiblePanel>
  );
}

function Row({ k, v }: { k: string; v: ReactNode }) {
  return (
    <div className="flex justify-between gap-4 border-b border-border/40 pb-2">
      <span className="shrink-0 text-muted">{k}</span>
      <span className="text-right font-medium">{v}</span>
    </div>
  );
}

function EquipmentGrid({ slots, title }: { slots: EqSlot[]; title: string }) {
  // Ordem legado: 2,1,3 / 6,4,5 / 9,7,10 / _,8 - feet (8) centralizado na 4a linha
  const cells: (EqSlot | null)[] = [...slots];
  // Inserir celula vazia antes do feet (slot 8) para centralizar
  const feetIdx = cells.findIndex((c) => c && c.slot === 8);
  if (feetIdx >= 0) {
    cells.splice(feetIdx, 0, null);
  }

  // BEGIN CHANGE: slots/itens maiores (48px) e bloco centralizado
  const slotPx = 48;
  const iconPx = 40;
  return (
    <div className="mx-auto w-fit">
      <div className="mb-2 text-center text-sm text-muted">{title}</div>
      <div
        className="inline-grid grid-cols-3 gap-1 rounded border border-black/80 p-1.5"
        style={{ backgroundImage: `url(${equipmentPanelBgUrl()})` }}
      >
        {cells.map((cell, i) => {
          if (!cell) {
            return (
              <div
                key={`empty-${i}`}
                style={{ width: slotPx, height: slotPx }}
              />
            );
          }
          const filled = cell.itemId != null && cell.itemId > 0;
          return (
            <div
              key={cell.slot}
              className="flex items-center justify-center"
              style={{
                width: slotPx,
                height: slotPx,
                ...(filled
                  ? { backgroundImage: `url(${equipmentEmptyBgUrl()})` }
                  : {}),
              }}
              title={filled ? `Item ${cell.itemId}` : `Slot ${cell.slot}`}
            >
              {filled ? (
                <ItemIcon id={cell.itemId!} size={iconPx} />
              ) : (
                // eslint-disable-next-line @next/next/no-img-element
                <img
                  src={equipmentSlotUrl(cell.slot)}
                  alt=""
                  width={iconPx}
                  height={iconPx}
                  className="object-contain"
                  style={{ width: iconPx, height: iconPx }}
                />
              )}
            </div>
          );
        })}
      </div>
    </div>
  );
  // END CHANGE
}

function KillerChip({ killer }: { killer: Killer }) {
  const countPrefix = killer.count > 1 ? `${killer.count}x ` : "";
  // Outfits maiores no painel de mortes (legado ~64px)
  const outfitSize = "row" as const;

  if (killer.type === "monster") {
    return (
      <span className="inline-flex items-center gap-2">
        <MonsterVisual
          look={killer.look}
          itemId={killer.itemId}
          alt={killer.monster}
          size={outfitSize}
        />
        <span>
          {countPrefix}
          {killer.monster}
        </span>
      </span>
    );
  }

  if (killer.type === "player") {
    const canLink = !killer.deleted;
    const inner = (
      <>
        {killer.look && (
          <Outfit look={killer.look} size={outfitSize} alt={killer.player} />
        )}
        <span className="font-medium">{killer.player}</span>
      </>
    );
    if (!canLink) {
      return <span className="inline-flex items-center gap-2">{inner}</span>;
    }
    return (
      <Link
        href={`/character/?name=${encodeURIComponent(killer.player)}`}
        className="inline-flex items-center gap-2 text-brand hover:underline"
      >
        {inner}
      </Link>
    );
  }

  // summon
  return (
    <span className="inline-flex flex-wrap items-center gap-2">
      <MonsterVisual
        look={killer.monsterLook}
        itemId={killer.monsterItem}
        alt={killer.monster}
        size={outfitSize}
      />
      <span>
        {countPrefix}
        {killer.monster}
      </span>
      <span className="text-muted">summoned by</span>
      <Link
        href={`/character/?name=${encodeURIComponent(killer.player)}`}
        className="inline-flex items-center gap-2 text-brand hover:underline"
      >
        {killer.playerLook && (
          <Outfit look={killer.playerLook} size={outfitSize} alt={killer.player} />
        )}
        <span className="font-medium">{killer.player}</span>
      </Link>
    </span>
  );
}

function MonsterVisual({
  look,
  itemId,
  alt,
  size = "row",
}: {
  look: Look | null;
  itemId: number | null;
  alt: string;
  size?: "inline" | "row" | "grid" | "profile";
}) {
  if (look && look.looktype > 0) {
    return <Outfit look={look} size={size} alt={alt} />;
  }
  if (itemId && itemId > 0) {
    return <ItemIcon id={itemId} size={40} alt={alt} />;
  }
  return null;
}
// END CHANGE
