﻿import { AnimatePresence, motion } from 'motion/react';
import { type CSSProperties, useEffect, useMemo, useState } from 'react';

import { formatAttributeList, resolveAttributeSchema, resolveCharacterAttributeProfile } from '../data/attributeResolver';
import {
  type BuildDamageBreakdown,
  describeBuildContribution,
  getBuildContributionAttributeRows,
  getBuildSourceLabel,
  getCompanionBuildDamageBreakdown,
  getPlayerBuildDamageBreakdown,
} from '../data/buildDamage';
import { getCharacterEquipment } from '../data/characterPresets';
import {
  buildInitialEquipmentLoadout,
  EQUIPMENT_SLOTS,
  getEquipmentRarityLabel,
  getEquipmentSlotLabel,
} from '../data/equipmentEffects';
import type { CharacterChatTarget } from '../hooks/useStoryGeneration';
import { getResourceLabelsForWorld } from '../services/customWorldPresentation';
import {
  AnimationState,
  Character,
  CompanionRenderState,
  CustomWorldProfile,
  EquipmentLoadout,
  GameState,
  QuestLogEntry,
  TimedBuildBuff,
  WorldAttributeSchema,
  WorldType,
} from '../types';
import { CHROME_ICONS, getEquipmentSlotIcon, getNineSliceStyle, UI_CHROME } from '../uiAssets';
import { AffinityStatusCard } from './AffinityStatusCard';
import { CharacterAnimator } from './CharacterAnimator';
import type { GameCanvasEntitySelection } from './GameCanvas';
import { PixelIcon } from './PixelIcon';

interface CharacterPanelProps {
  worldType: WorldType | null;
  customWorldProfile?: CustomWorldProfile | null;
  playerCharacter: Character;
  playerHp: number;
  playerMaxHp: number;
  playerMana: number;
  playerMaxMana: number;
  playerEquipment: EquipmentLoadout;
  activeBuildBuffs?: TimedBuildBuff[];
  companionRenderStates: CompanionRenderState[];
  npcStates?: GameState['npcStates'];
  quests: QuestLogEntry[];
  onOpenCamp?: () => void;
  onOpenCharacterChat?: (target: CharacterChatTarget) => void;
  chatSummaries?: Record<string, string>;
  onInspectMember?: (selection: GameCanvasEntitySelection) => void;
}

type PartyMember = {
  id: string;
  npcId: string | null;
  renderState: CompanionRenderState | null;
  character: Character;
  roleLabel: string;
  hp: number;
  maxHp: number;
  mana: number;
  maxMana: number;
  isLeader: boolean;
};

type EquipmentRow = {
  key: string;
  slotLabel: string;
  itemLabel: string;
  rarityLabel: string;
};

type ContributionRow = BuildDamageBreakdown['rows'][number];

function clamp(value: number, min: number, max: number) {
  return Math.min(max, Math.max(min, value));
}

function StatusRow({
  label,
  current,
  max,
  tone,
}: {
  label: string;
  current: number;
  max: number;
  tone: 'hp' | 'mp';
}) {
  const ratio = Math.max(0, Math.min(1, max > 0 ? current / max : 0));
  const fillClass = tone === 'hp'
    ? 'from-emerald-400 via-lime-300 to-emerald-200'
    : 'from-sky-500 via-cyan-300 to-sky-100';

  return (
    <div className="space-y-1">
      <div className="flex items-center justify-between gap-3 text-[10px] uppercase tracking-[0.16em] text-zinc-400">
        <span>{label}</span>
        <span className="text-zinc-200">{current} / {max}</span>
      </div>
      <div className="h-2 overflow-hidden rounded-full border border-white/10 bg-black/45">
        <div className={`h-full bg-gradient-to-r ${fillClass}`} style={{ width: `${ratio * 100}%` }} />
      </div>
    </div>
  );
}

function getGenderLabel(gender: Character['gender']) {
  if (gender === 'female') return '女';
  if (gender === 'male') return '男';
  return '未明';
}

const SKILL_STYLE_LABELS = {
  burst: '爆发',
  steady: '稳态',
  mobility: '机动',
  finisher: '终结',
  projectile: '投射',
} satisfies Record<Character['skills'][number]['style'], string>;

function getSkillDeliveryLabel(skill: Character['skills'][number]) {
  return skill.delivery === 'ranged' || skill.style === 'projectile' ? '远程' : '近战';
}

function CharacterSkillsList({character}: {character: Character}) {
  if (character.skills.length === 0) {
    return <div className="rounded-lg border border-white/5 bg-black/20 px-3 py-3 text-sm text-zinc-500">暂无技能信息</div>;
  }

  return (
    <div className="grid gap-2 sm:grid-cols-2">
      {character.skills.map(skill => (
        <div key={skill.id} className="rounded-lg border border-white/5 bg-black/20 px-3 py-3 text-sm text-zinc-300">
          <div className="flex items-center justify-between gap-2">
            <div className="font-semibold text-white">{skill.name}</div>
            <span className="rounded-full border border-white/10 bg-white/6 px-2 py-0.5 text-[10px] text-zinc-100">
              {getSkillDeliveryLabel(skill)}
            </span>
          </div>
          <div className="mt-2 grid grid-cols-2 gap-2 text-[11px] text-zinc-400">
            <div>伤害：{skill.damage}</div>
            <div>法力：{skill.manaCost}</div>
            <div>冷却：{skill.cooldownTurns}</div>
            <div>距离：{skill.range}</div>
          </div>
          <div className="mt-2 text-[10px] tracking-[0.16em] text-sky-200/85">{SKILL_STYLE_LABELS[skill.style]}</div>
        </div>
      ))}
    </div>
  );
}

function getContributionHeatRatio(value: number, minValue = 0, maxValue = 1) {
  const normalizedMin = Number.isFinite(minValue) ? minValue : 0;
  const normalizedMax = Number.isFinite(maxValue) ? maxValue : 1;
  const range = normalizedMax - normalizedMin;

  if (range <= 0.0001) {
    return normalizedMax > 0 ? 1 : 0;
  }

  return clamp((value - normalizedMin) / range, 0, 1);
}

function getContributionVisualStyle(value: number, minValue = 0, maxValue = 1): CSSProperties {
  const ratio = getContributionHeatRatio(value, minValue, maxValue);
  const hue = 210 - ratio * 178;
  const saturation = 62 + ratio * 16;
  const lightness = 56 + ratio * 6;

  return {
    borderColor: `hsla(${hue}, ${saturation + 6}%, ${lightness}%, ${0.22 + ratio * 0.28})`,
    background: `linear-gradient(135deg, hsla(${hue}, ${saturation + 10}%, ${36 + ratio * 12}%, ${0.18 + ratio * 0.22}) 0%, rgba(12, 16, 24, 0.94) 72%)`,
    boxShadow: `inset 0 1px 0 rgba(255,255,255,0.04), 0 0 ${10 + ratio * 20}px hsla(${hue}, ${saturation + 14}%, ${58 + ratio * 8}%, ${0.12 + ratio * 0.18})`,
    color: ratio > 0.76 ? 'rgb(255 244 235)' : ratio > 0.32 ? 'rgb(236 242 248)' : 'rgb(203 213 225)',
  };
}

function getContributionTrackStyle(value: number, minValue = 0, maxValue = 1): CSSProperties {
  const ratio = getContributionHeatRatio(value, minValue, maxValue);
  const widthRatio = 0.18 + ratio * 0.82;
  const hue = 210 - ratio * 178;

  return {
    width: `${widthRatio * 100}%`,
    background: `linear-gradient(90deg, hsla(${hue}, ${70 + ratio * 14}%, ${56 + ratio * 10}%, 0.94) 0%, rgba(255, 229, 214, 0.98) 100%)`,
  };
}

function MultiplierContributionList({
  breakdown,
  schema,
  onSelectContribution,
}: {
  breakdown: BuildDamageBreakdown;
  schema: WorldAttributeSchema;
  onSelectContribution: (row: ContributionRow) => void;
}) {
  const sortedRows = [...breakdown.rows].sort((left, right) => right.bonusDelta - left.bonusDelta || left.label.localeCompare(right.label, 'zh-CN'));
  const contributionProducts = sortedRows.map(row => row.bonusDelta);
  const weakestProduct = contributionProducts.length > 0 ? Math.min(...contributionProducts) : 0;
  const strongestProduct = contributionProducts.length > 0 ? Math.max(...contributionProducts) : 1;

  return (
    <div className="space-y-3 rounded-xl border border-sky-400/12 bg-sky-500/6 px-3 py-3">
      <div className="flex items-center justify-between gap-3 text-[10px] uppercase tracking-[0.16em] text-sky-100/80">
        <span>{'\u5c5e\u6027\u9002\u914d\u5ea6'}</span>
        <span className="text-zinc-400">{'\u70b9\u51fb\u6807\u7b7e\u67e5\u770b\u6536\u76ca\u6765\u81ea\u54ea\u4e9b\u5c5e\u6027'}</span>
      </div>
      <div className="flex justify-center">
        <div className="w-full max-w-[12rem] rounded-xl border border-white/8 bg-black/20 px-3 py-2 text-center">
          <div className="text-[10px] uppercase tracking-[0.16em] text-zinc-500">{'\u5c5e\u6027\u9002\u914d\u500d\u7387'}</div>
          <div className="mt-1 text-sm font-semibold tabular-nums text-emerald-100">x{breakdown.buildDamageMultiplier.toFixed(2)}</div>
          <div className="mt-1 text-[10px] text-zinc-500">{'\u603b\u52a0\u6210'} +{breakdown.buildDamageBonus.toFixed(2)}</div>
        </div>
      </div>
      {sortedRows.length > 0 ? (
        <div className="flex flex-wrap gap-2">
          {sortedRows.map(row => (
            <button
              key={`formula-tag-${row.label}`}
              type="button"
              onClick={() => onSelectContribution(row)}
              className="min-w-[6.25rem] rounded-xl border px-3 py-2 text-left text-[10px] text-white transition-transform hover:-translate-y-0.5"
              style={getContributionVisualStyle(row.bonusDelta, weakestProduct, strongestProduct)}
              title={`\u67e5\u770b ${row.label} \u7684\u5c5e\u6027\u9002\u914d\u660e\u7ec6`}
            >
              <div className="flex items-center justify-between gap-2">
                <span className="font-medium">{row.label}</span>
                <span className="text-[11px] font-semibold tabular-nums text-current/80">+{row.bonusDelta.toFixed(2)}</span>
              </div>
              <div className="mt-1 text-[10px] leading-4 text-current/70">
                {getBuildSourceLabel(row.source)} · {describeBuildContribution(row, schema)}
              </div>
              <div className="mt-2 h-1.5 overflow-hidden rounded-full bg-black/35">
                <div className="h-full rounded-full" style={getContributionTrackStyle(row.bonusDelta, weakestProduct, strongestProduct)} />
              </div>
            </button>
          ))}
        </div>
      ) : (
        <span className="rounded-full border border-white/10 bg-black/20 px-2 py-1 text-[10px] text-zinc-300">
          {'\u5f53\u524d\u8fd8\u6ca1\u6709\u5f62\u6210\u6709\u6548\u6807\u7b7e'}
        </span>
      )}
    </div>
  );
}

function buildLeaderEquipmentRows(playerCharacter: Character, playerEquipment: EquipmentLoadout): EquipmentRow[] {
  const starterLoadout = buildInitialEquipmentLoadout(playerCharacter);
  return EQUIPMENT_SLOTS.map(slot => {
    const equippedItem = playerEquipment[slot] ?? starterLoadout[slot];
    return {
      key: `leader-${slot}`,
      slotLabel: getEquipmentSlotLabel(slot),
      itemLabel: equippedItem?.name ?? '绌轰綅',
      rarityLabel: equippedItem ? getEquipmentRarityLabel(equippedItem.rarity) : '绌轰綅',
    };
  });
}

function buildCompanionEquipmentRows(character: Character, keyPrefix: string): EquipmentRow[] {
  return getCharacterEquipment(character).map(item => ({
    key: `${keyPrefix}-${item.slot}-${item.item}`,
    slotLabel: item.slot,
    itemLabel: item.item,
    rarityLabel: item.rarity,
  }));
}

function getCharacterDetailSpriteStyle(character: Character) {
  const groundOffset = character.groundOffsetY ?? 22;
  const translateY = Math.max(10, Math.round((groundOffset - 22) * 0.34));

  return {
    transform: `translateY(${translateY}px) scale(1.34)`,
    transformOrigin: 'center bottom',
  } satisfies CSSProperties;
}

export function CharacterPanel({
  worldType,
  customWorldProfile = null,
  playerCharacter,
  playerHp,
  playerMaxHp,
  playerMana,
  playerMaxMana,
  playerEquipment,
  activeBuildBuffs = [],
  companionRenderStates,
  npcStates = {},
  quests,
  onInspectMember,
}: CharacterPanelProps) {
  const [selectedMemberId, setSelectedMemberId] = useState<string | null>(null);
  const [selectedContributionLabel, setSelectedContributionLabel] = useState<string | null>(null);

  const partyMembers = useMemo<PartyMember[]>(
    () => [
      {
        id: `leader-${playerCharacter.id}`,
        npcId: null,
        renderState: null,
        character: playerCharacter,
        roleLabel: '闃熼暱',
        hp: playerHp,
        maxHp: playerMaxHp,
        mana: playerMana,
        maxMana: playerMaxMana,
        isLeader: true,
      },
      ...companionRenderStates.map(companion => ({
        id: companion.npcId,
        npcId: companion.npcId,
        renderState: companion,
        character: companion.character,
        roleLabel: '鍚岃',
        hp: companion.hp,
        maxHp: companion.maxHp,
        mana: companion.mana,
        maxMana: companion.maxMana,
        isLeader: false,
      })),
    ],
    [companionRenderStates, playerCharacter, playerHp, playerMaxHp, playerMana, playerMaxMana],
  );

  const selectedMember = useMemo(
    () => partyMembers.find(member => member.id === selectedMemberId) ?? null,
    [partyMembers, selectedMemberId],
  );

  const activeQuests = useMemo(
    () => quests.filter(quest => quest.status !== 'turned_in'),
    [quests],
  );

  const buildBreakdownByMemberId = useMemo(
    () => Object.fromEntries(
      partyMembers.map(member => [
        member.id,
        member.isLeader
          ? getPlayerBuildDamageBreakdown({
              worldType,
              customWorldProfile,
              playerEquipment,
              activeBuildBuffs,
            } as GameState, playerCharacter)
          : getCompanionBuildDamageBreakdown(member.character, worldType, customWorldProfile),
      ]),
    ) as Record<string, BuildDamageBreakdown>,
    [activeBuildBuffs, customWorldProfile, partyMembers, playerCharacter, playerEquipment, worldType],
  );

  const selectedBuildBreakdown = selectedMember ? buildBreakdownByMemberId[selectedMember.id] ?? null : null;
  const selectedContributionRow = selectedBuildBreakdown?.rows.find(row => row.label === selectedContributionLabel) ?? null;
  const selectedContributionProducts = selectedBuildBreakdown?.rows.map(row => row.bonusDelta) ?? [];
  const selectedContributionMinProduct = selectedContributionProducts.length > 0 ? Math.min(...selectedContributionProducts) : 0;
  const selectedContributionMaxProduct = selectedContributionProducts.length > 0 ? Math.max(...selectedContributionProducts) : 1;
  const selectedAttributeSchema = resolveAttributeSchema(worldType, customWorldProfile);
  const selectedMemberAffinity = selectedMember?.npcId
    ? npcStates[selectedMember.npcId]?.affinity ?? 0
    : null;
  const selectedEquipmentRows = selectedMember
    ? selectedMember.isLeader
      ? buildLeaderEquipmentRows(playerCharacter, playerEquipment)
      : buildCompanionEquipmentRows(selectedMember.character, selectedMember.id)
    : [];
  const selectedAttributeRows = selectedMember
      ? formatAttributeList(
        resolveCharacterAttributeProfile(selectedMember.character, worldType, customWorldProfile),
        selectedAttributeSchema,
      )
    : [];
  const selectedContributionAttributes = selectedContributionRow
    ? getBuildContributionAttributeRows(selectedContributionRow, selectedAttributeSchema)
    : [];

  const resourceLabels = getResourceLabelsForWorld(worldType);

  useEffect(() => {
    if (!selectedContributionLabel) return;
    if (!selectedContributionRow) {
      setSelectedContributionLabel(null);
    }
  }, [selectedContributionLabel, selectedContributionRow]);

  useEffect(() => {
    if (!onInspectMember || !selectedMemberId) return;
    setSelectedMemberId(null);
  }, [onInspectMember, selectedMemberId]);

  const handleMemberInspect = (member: PartyMember) => {
    if (onInspectMember) {
      if (member.isLeader) {
        onInspectMember({ kind: 'player' });
        return;
      }

      if (member.renderState) {
        onInspectMember({ kind: 'companion', companion: member.renderState });
        return;
      }
    }

    setSelectedMemberId(member.id);
  };

  return (
    <>
      <div className="flex min-h-0 flex-1 flex-col">
        <div className="pixel-nine-slice pixel-panel min-h-0 flex-1" style={getNineSliceStyle(UI_CHROME.panel, { paddingX: 14, paddingY: 12 })}>
          {activeQuests.length > 0 && (
            <div className="mb-3 rounded-xl border border-sky-400/15 bg-sky-500/8 px-3 py-3">
              <div className="mb-2 text-xs font-bold text-sky-100">褰撳墠濮旀墭</div>
              <div className="space-y-2">
                {activeQuests.map(quest => (
                  <div key={quest.id} className="rounded-lg border border-white/6 bg-black/18 px-3 py-2 text-sm text-zinc-200">
                    <div className="font-semibold text-white">{quest.title}</div>
                    <div className="mt-1 text-xs text-zinc-400">{quest.summary}</div>
                  </div>
                ))}
              </div>
            </div>
          )}

          <div className="mb-3 text-xs font-bold text-white">队伍成员</div>
          <div className="grid max-h-[calc(100vh-14rem)] grid-cols-1 gap-3 overflow-y-auto pr-1 scrollbar-hide sm:max-h-[calc(100vh-18rem)] md:grid-cols-2">
            {partyMembers.map(member => (
              <button
                key={member.id}
                type="button"
                onClick={() => handleMemberInspect(member)}
                className="w-full px-0 py-1 text-left transition-opacity hover:opacity-90"
              >
                <div className="flex items-start gap-3 rounded-xl border border-white/6 bg-black/18 px-3 py-3">
                  <div className="flex h-14 w-14 shrink-0 items-center justify-center overflow-hidden rounded-xl bg-transparent sm:h-16 sm:w-16">
                    <img
                      src={member.character.portrait}
                      alt={member.character.name}
                      className="h-full w-full scale-125 object-contain object-bottom"
                      style={{ imageRendering: 'pixelated' }}
                    />
                  </div>

                  <div className="min-w-0 flex-1">
                    <div className="flex items-center justify-between gap-3">
                      <div className="min-w-0">
                        <div className="truncate text-sm font-semibold text-white">{member.character.name}</div>
                        <div className="truncate text-[10px] tracking-[0.16em] text-zinc-500">{member.character.title}</div>
                      </div>
                      <span className={`rounded-full px-2 py-0.5 text-[10px] ${member.isLeader ? 'bg-amber-500/10 text-amber-100' : 'bg-sky-500/10 text-sky-100'}`}>
                        {member.roleLabel}
                      </span>
                    </div>
                    <div className="mt-2.5 space-y-2.5">
                      <StatusRow label={resourceLabels.hp} current={member.hp} max={member.maxHp} tone="hp" />
                      <StatusRow label={resourceLabels.mp} current={member.mana} max={member.maxMana} tone="mp" />
                    </div>
                    <div className="mt-2 flex items-center justify-end gap-2 text-[11px] text-zinc-400">
                      <span className="rounded-full border border-white/10 bg-black/20 px-2 py-0.5 text-zinc-200">
                        {buildBreakdownByMemberId[member.id]?.baseTagCount ?? 0} 标签
                      </span>
                      <span className="rounded-full border border-emerald-400/20 bg-emerald-500/10 px-2 py-0.5 text-emerald-100">
                        {'\u9002\u914d'} x{buildBreakdownByMemberId[member.id]?.buildDamageMultiplier.toFixed(2) ?? '1.00'}
                      </span>
                    </div>
                  </div>
                </div>
              </button>
            ))}
          </div>
        </div>
      </div>

      <AnimatePresence>
        {selectedContributionRow && selectedMember && (
          <motion.div
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
            className="fixed inset-0 z-[75] flex items-center justify-center bg-black/72 p-4 backdrop-blur-sm"
            onClick={() => setSelectedContributionLabel(null)}
          >
            <motion.div
              initial={{ opacity: 0, scale: 0.96, y: 8 }}
              animate={{ opacity: 1, scale: 1, y: 0 }}
              exit={{ opacity: 0, scale: 0.96, y: 8 }}
              transition={{ duration: 0.18, ease: 'easeOut' }}
              className="pixel-nine-slice pixel-modal-shell flex max-h-[min(88vh,40rem)] w-full max-w-xl flex-col overflow-hidden shadow-[0_24px_80px_rgba(0,0,0,0.55)]"
              style={getNineSliceStyle(UI_CHROME.modalPanel)}
              onClick={event => event.stopPropagation()}
            >
              <div className="relative border-b border-white/10 px-4 py-3 sm:px-5 sm:py-4">
                <div className="min-w-0 pr-10">
                  <div className="text-[10px] tracking-[0.22em] text-sky-300/80">{'\u5c5e\u6027\u9002\u914d\u89e3\u6790'}</div>
                  <div className="mt-1 truncate text-sm font-semibold text-white">{selectedContributionRow.label}</div>
                  <div className="mt-1 text-[10px] tracking-[0.18em] text-zinc-500">{selectedMember.character.name}</div>
                </div>
                <button
                  type="button"
                  onClick={() => setSelectedContributionLabel(null)}
                  className="absolute right-4 top-3 p-1 text-zinc-400 transition-colors hover:text-white sm:right-5 sm:top-4"
                >
                  <PixelIcon src={CHROME_ICONS.close} className="h-4 w-4" />
                </button>
              </div>

              <div className="space-y-4 overflow-y-auto p-4 sm:p-5">
                <div className="rounded-xl border px-4 py-4" style={getContributionVisualStyle(selectedContributionRow.bonusDelta, selectedContributionMinProduct, selectedContributionMaxProduct)}>
                  <div className="flex items-center justify-between gap-3">
                    <div>
                      <div className="text-sm font-semibold">{selectedContributionRow.label}</div>
                      <div className="mt-1 text-xs text-current/70">
                        {getBuildSourceLabel(selectedContributionRow.source)} · {describeBuildContribution(selectedContributionRow, selectedAttributeSchema)}
                      </div>
                    </div>
                    <div className="text-right">
                      <div className="text-sm font-semibold">{'\u52a0\u6210'} +{selectedContributionRow.bonusDelta.toFixed(2)}</div>
                      <div className="mt-1 text-[11px] text-current/70">{'\u9002\u914d\u5ea6'} {Math.round(selectedContributionRow.fitScore * 100)}%</div>
                    </div>
                  </div>
                  <div className="mt-3 h-2 overflow-hidden rounded-full bg-black/35">
                    <div className="h-full rounded-full" style={getContributionTrackStyle(selectedContributionRow.bonusDelta, selectedContributionMinProduct, selectedContributionMaxProduct)} />
                  </div>
                </div>

                <div className="rounded-xl border border-white/8 bg-black/20 px-4 py-3 text-sm leading-6 text-zinc-300">
                  <div className="font-medium text-white">bonusDelta = {'\u5404\u5c5e\u6027\u52a0\u6210\u4e4b\u548c'}</div>
                  <div className="mt-1 text-zinc-400">
                    {'\u6bcf\u4e2a\u6807\u7b7e\u90fd\u4f1a\u5206\u522b\u5339\u914d\u5f53\u524d\u4e16\u754c\u7684\u5c5e\u6027\u8f74\uff0c\u518d\u548c\u89d2\u8272\u81ea\u5df1\u7684\u5c5e\u6027\u6743\u91cd\u9010\u9879\u76f8\u4e58\u3002\u6bcf\u6761\u5c5e\u6027\u5148\u751f\u6210\u5355\u72ec\u7684\u52a0\u6210\uff0c\u6700\u540e\u6c47\u603b\u6210\u8fd9\u4e2a\u6807\u7b7e\u7684\u6536\u76ca\u3002'}
                  </div>
                  <div className="mt-2 font-medium text-zinc-200">
                    {selectedContributionRow.label} = 0.12 x {'\u9002\u914d\u5ea6'} {selectedContributionRow.fitScore.toFixed(2)} x {'\u6765\u6e90\u7cfb\u6570'} {selectedContributionRow.sourceCoefficient.toFixed(2)} = {selectedContributionRow.bonusDelta.toFixed(2)}
                  </div>
                </div>

                {selectedContributionAttributes.length > 0 ? (
                  <div className="space-y-2">
                    {selectedContributionAttributes.map(attribute => (
                        <div key={`${selectedContributionRow.label}-${attribute.slotId}`} className="rounded-xl border border-white/8 bg-black/20 px-4 py-3">
                          <div className="flex items-center justify-between gap-3 text-sm text-zinc-200">
                            <span>{attribute.label}</span>
                            <span>{Math.round(attribute.percent * 100)}%</span>
                          </div>
                          <div className="mt-1 text-[11px] leading-5 text-zinc-500">
                            {attribute.definition}
                          </div>
                          <div className="mt-2 grid gap-1 text-[11px] text-zinc-400 sm:grid-cols-2">
                            <div>{'\u6807\u7b7e\u4eb2\u548c'} {Math.round(attribute.similarity * 100)}%</div>
                            <div>{'\u89d2\u8272\u6743\u91cd'} {Math.round(attribute.weight * 100)}%</div>
                            <div>{'\u9002\u914d\u8d21\u732e'} {attribute.value.toFixed(4)}</div>
                            <div>{'\u5c5e\u6027\u52a0\u6210'} +{attribute.modifierDelta.toFixed(4)}</div>
                          </div>
                          <div className="mt-2 h-1.5 overflow-hidden rounded-full bg-black/35">
                            <div className="h-full rounded-full" style={getContributionTrackStyle(attribute.percent)} />
                          </div>
                        </div>
                      ))}
                  </div>
                ) : (
                  <div className="rounded-xl border border-white/8 bg-black/20 px-4 py-3 text-sm leading-6 text-zinc-400">
                    {'\u5f53\u524d\u6807\u7b7e\u8fd8\u6ca1\u6709\u53ef\u5c55\u793a\u7684\u5c5e\u6027\u9002\u914d\u660e\u7ec6\u3002'}
                  </div>
                )}
              </div>
            </motion.div>
          </motion.div>
        )}
      </AnimatePresence>

      <AnimatePresence>
        {selectedMember && (
          <motion.div
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
            className="fixed inset-0 z-[70] flex items-center justify-center bg-black/72 p-4 backdrop-blur-sm"
            onClick={() => setSelectedMemberId(null)}
          >
            <motion.div
              initial={{ opacity: 0, scale: 0.96, y: 8 }}
              animate={{ opacity: 1, scale: 1, y: 0 }}
              exit={{ opacity: 0, scale: 0.96, y: 8 }}
              transition={{ duration: 0.18, ease: 'easeOut' }}
              className="pixel-nine-slice pixel-modal-shell flex max-h-[min(92vh,56rem)] w-full max-w-3xl flex-col overflow-hidden shadow-[0_24px_80px_rgba(0,0,0,0.55)]"
              style={getNineSliceStyle(UI_CHROME.modalPanel)}
              onClick={event => event.stopPropagation()}
            >
              <div className="relative border-b border-white/10 px-4 py-3 sm:px-5 sm:py-4">
                <div className="min-w-0 pr-10">
                  <div className="text-[10px] tracking-[0.22em] text-sky-300/80">角色详情</div>
                  <div className="mt-1 truncate text-sm font-semibold text-white">{selectedMember.character.name}</div>
                  <div className="mt-1 flex items-center gap-2 text-[10px] tracking-[0.2em] text-zinc-500">
                    <span>{selectedMember.character.title}</span>
                    <span className="rounded-full border border-white/10 bg-black/20 px-2 py-0.5 text-[9px] text-zinc-200">
                      {getGenderLabel(selectedMember.character.gender)}
                    </span>
                  </div>
                </div>
                <button
                  type="button"
                  onClick={() => setSelectedMemberId(null)}
                  className="absolute right-4 top-3 p-1 text-zinc-400 transition-colors hover:text-white sm:right-5 sm:top-4"
                >
                  <PixelIcon src={CHROME_ICONS.close} className="h-4 w-4" />
                </button>
              </div>

              <div className="grid min-h-0 flex-1 gap-4 overflow-y-auto p-4 sm:p-5 lg:grid-cols-[minmax(0,0.82fr)_minmax(0,1.18fr)] lg:overflow-hidden">
                <div className="space-y-4 lg:max-h-full lg:overflow-y-auto lg:pr-1">
                  <div className="pixel-nine-slice pixel-panel" style={getNineSliceStyle(UI_CHROME.panel)}>
                    <div className="flex flex-col items-center text-center">
                      <div className="flex h-36 w-full max-w-[15rem] items-end justify-center overflow-hidden rounded-2xl border border-white/10 bg-black/20 sm:h-40">
                        <CharacterAnimator
                          state={AnimationState.IDLE}
                          character={selectedMember.character}
                          className="h-full w-full"
                          imageClassName="object-bottom"
                          style={getCharacterDetailSpriteStyle(selectedMember.character)}
                        />
                      </div>
                      <div className="mt-3 text-base font-bold text-white">{selectedMember.character.name}</div>
                      <div className="mt-1 text-[10px] tracking-[0.2em] text-zinc-500">{selectedMember.character.title}</div>
                      <p className="mt-3 text-sm leading-relaxed text-zinc-300">{selectedMember.character.description}</p>
                    </div>
                  </div>

                  <div className="pixel-nine-slice pixel-panel" style={getNineSliceStyle(UI_CHROME.statsPanel)}>
                    <div className="mb-3 text-xs font-bold text-white">状态</div>
                    <div className="space-y-3">
                      <StatusRow label={resourceLabels.hp} current={selectedMember.hp} max={selectedMember.maxHp} tone="hp" />
                      <StatusRow label={resourceLabels.mp} current={selectedMember.mana} max={selectedMember.maxMana} tone="mp" />
                      {selectedMemberAffinity != null && (
                        <AffinityStatusCard affinity={selectedMemberAffinity} />
                      )}
                      {selectedBuildBreakdown && (
                        <MultiplierContributionList
                          breakdown={selectedBuildBreakdown}
                          schema={selectedAttributeSchema}
                          onSelectContribution={row => setSelectedContributionLabel(row.label)}
                        />
                      )}
                    </div>
                    <div className="mt-4 grid grid-cols-2 gap-2 text-sm text-zinc-300">
                      {selectedAttributeRows.map(({ slot, value }) => (
                        <div key={slot.slotId} className="rounded-lg border border-white/5 bg-black/20 px-3 py-2">
                          <div>{slot.name}: {value}</div>
                          <div className="mt-1 text-[10px] leading-relaxed text-zinc-500">{slot.definition}</div>
                        </div>
                      ))}
                    </div>
                  </div>
                </div>

                <div className="space-y-4 lg:min-h-0 lg:overflow-y-auto lg:pr-1">
                  <div className="pixel-nine-slice pixel-panel" style={getNineSliceStyle(UI_CHROME.panel)}>
                    <div className="mb-3 text-xs font-bold text-white">背景故事</div>
                    <div className="rounded-xl border border-white/8 bg-black/18 px-4 py-3 text-sm leading-relaxed text-zinc-300">
                      {selectedMember.character.backstory}
                    </div>
                  </div>

                  <div className="pixel-nine-slice pixel-panel" style={getNineSliceStyle(UI_CHROME.panel)}>
                    <div className="mb-3 text-xs font-bold text-white">性格</div>
                    <div className="rounded-xl border border-white/8 bg-black/18 px-4 py-3 text-sm leading-relaxed text-zinc-300">
                      {selectedMember.character.personality}
                    </div>
                  </div>

                  <div className="pixel-nine-slice pixel-panel" style={getNineSliceStyle(UI_CHROME.panel)}>
                    <div className="mb-3 text-xs font-bold text-white">{'\u6280\u80fd'}</div>
                    <CharacterSkillsList character={selectedMember.character} />
                  </div>

                  <div className="pixel-nine-slice pixel-panel" style={getNineSliceStyle(UI_CHROME.panel)}>
                    <div className="mb-3 text-xs font-bold text-white">装备</div>
                    <div className="space-y-2 text-sm text-zinc-300">
                      {selectedEquipmentRows.map(item => (
                        <div
                          key={item.key}
                          className="flex items-center justify-between rounded-lg border border-white/5 bg-black/20 px-3 py-2"
                        >
                          <div className="flex items-center gap-3">
                            <PixelIcon src={getEquipmentSlotIcon(item.slotLabel)} className="h-8 w-8" />
                            <div>
                              <div className="text-[10px] tracking-[0.2em] text-zinc-500">{item.slotLabel}</div>
                              <div>{item.itemLabel}</div>
                            </div>
                          </div>
                          <span className="rounded-full border border-amber-500/20 bg-amber-500/10 px-2 py-0.5 text-[10px] text-amber-100">
                            {item.rarityLabel}
                          </span>
                        </div>
                      ))}
                    </div>
                  </div>
                </div>
              </div>
            </motion.div>
          </motion.div>
        )}
      </AnimatePresence>
    </>
  );
}


