import { useCallback, useEffect, useRef, useState, type CSSProperties } from 'react';
import { BuffType, type ActiveBuff, type BuffChargeState } from '../game/types';
import { BUFF_COOLDOWN_MS, buffMaxChargesForHero } from '../network/buffMap';
import { BUFF_VISUAL, buffUiStrings } from './buffMeta';
import { purchaseBuffRefill } from '../network/api';
import type { HeroResponse } from '../network/api';
import { getTelegramUserId } from '../shared/telegram';
import { useT, t } from '../i18n';

// ---- Types ----

interface BuffBarProps {
  buffs: ActiveBuff[];
  /** Client-side cooldown end timestamps (ms); backend does not persist these yet. */
  cooldownEndsAt: Partial<Record<BuffType, number>>;
  /** Per-buff charge quotas from the server. */
  buffCharges: Partial<Record<BuffType, BuffChargeState>>;
  /** When true, UI max charge labels use subscriber caps (×2). */
  subscriptionActive?: boolean;
  /** When true (e.g. hero dead), buff taps do nothing and refill flow is blocked. */
  buffsLocked?: boolean;
  nowMs: number;
  onActivate: (type: BuffType) => void;
  /** Called when a buff refill purchase returns an updated hero */
  onHeroUpdated?: (hero: HeroResponse) => void;
}

interface BuffButtonProps {
  buff: ActiveBuff;
  charge: BuffChargeState | undefined;
  maxCharges: number;
  onActivate: () => void;
  onRefill?: (type: BuffType) => void;
  nowMs: number;
  buffsLocked?: boolean;
}

// ---- Tooltip ----

const LONG_PRESS_MS = 400;
const TOOLTIP_AUTO_HIDE_MS = 2500;

/** When false, the green refill CTA in the hover tooltip is hidden (purchase still reachable from tap flow if any). */
const SHOW_BUFF_REFILL_BUTTON_IN_TOOLTIP = false;

const tooltipStyle: CSSProperties = {
  position: 'absolute',
  bottom: '110%',
  left: '50%',
  transform: 'translateX(-50%)',
  padding: '6px 10px',
  borderRadius: 8,
  backgroundColor: 'rgba(10, 10, 20, 0.92)',
  border: '1px solid rgba(255,255,255,0.15)',
  color: '#eee',
  fontSize: 11,
  fontWeight: 600,
  whiteSpace: 'nowrap',
  pointerEvents: 'none',
  zIndex: 100,
  textAlign: 'center',
  lineHeight: 1.4,
  boxShadow: '0 4px 12px rgba(0,0,0,0.5)',
};

const tooltipArrow: CSSProperties = {
  position: 'absolute',
  bottom: -5,
  left: '50%',
  transform: 'translateX(-50%)',
  width: 0,
  height: 0,
  borderLeft: '5px solid transparent',
  borderRight: '5px solid transparent',
  borderTop: '5px solid rgba(10, 10, 20, 0.92)',
};

// ---- Charge Badge ----

const chargeBadgeBase: CSSProperties = {
  position: 'absolute',
  top: -4,
  right: -4,
  minWidth: 16,
  height: 16,
  borderRadius: 8,
  display: 'flex',
  alignItems: 'center',
  justifyContent: 'center',
  fontSize: 9,
  fontWeight: 700,
  lineHeight: 1,
  padding: '0 3px',
  zIndex: 10,
  pointerEvents: 'none',
  border: '1px solid rgba(0,0,0,0.4)',
};

// ---- Radial Cooldown SVG ----

function RadialCooldown({ progress }: { progress: number }) {
  if (progress <= 0) return null;

  const radius = 22;
  const cx = 25;
  const cy = 25;
  const circumference = 2 * Math.PI * radius;
  const offset = circumference * (1 - progress);

  return (
    <svg
      style={{
        position: 'absolute',
        top: 0,
        left: 0,
        width: '100%',
        height: '100%',
        transform: 'rotate(-90deg)',
        pointerEvents: 'none',
      }}
      viewBox="0 0 50 50"
    >
      <circle
        cx={cx}
        cy={cy}
        r={radius}
        fill="rgba(0,0,0,0.5)"
        stroke="none"
        strokeDasharray={circumference}
        strokeDashoffset={offset}
      />
      <circle
        cx={cx}
        cy={cy}
        r={radius}
        fill="none"
        stroke="rgba(255,255,255,0.3)"
        strokeWidth={2}
        strokeDasharray={circumference}
        strokeDashoffset={offset}
        strokeLinecap="round"
      />
    </svg>
  );
}

// ---- Helpers ----

/** Format an ISO timestamp as HH:MM in local time. */
function formatTimeHHMM(iso: string): string {
  const d = new Date(iso);
  if (isNaN(d.getTime())) return '??:??';
  return d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
}

// ---- Buff Button ----

const buttonBase: CSSProperties = {
  position: 'relative',
  border: '2px solid rgba(255,255,255,0.2)',
  backgroundColor: 'rgba(0,0,0,0.5)',
  display: 'flex',
  alignItems: 'center',
  justifyContent: 'center',
  flexDirection: 'column',
  cursor: 'pointer',
  userSelect: 'none',
  WebkitTapHighlightColor: 'transparent',
};

function BuffButton({ buff, charge, maxCharges, onActivate, onRefill, nowMs, buffsLocked }: BuffButtonProps) {
  const tr = useT();
  const visual = BUFF_VISUAL[buff.type];
  const { label, desc } = buffUiStrings(tr, buff.type);
  const meta = { ...visual, label, desc };
  const [pressed, setPressed] = useState(false);
  const [showTooltip, setShowTooltip] = useState(false);
  const [showRefillConfirm, setShowRefillConfirm] = useState(false);
  const longPressTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
  const autoHideTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
  const didLongPress = useRef(false);

  const remainingEffectMs =
    buff.expiresAtMs != null ? Math.max(0, buff.expiresAtMs - nowMs) : buff.remainingMs;
  const isActive = remainingEffectMs > 0;

  const isOnCooldown = buff.cooldownRemainingMs > 0;
  const cooldownProgress =
    buff.cooldownMs > 0 ? buff.cooldownRemainingMs / buff.cooldownMs : 0;

  const cdSec = Math.ceil((buff.cooldownMs || 0) / 1000);

  // Charge state
  const remaining = charge?.remaining;
  const hasChargeData = remaining != null;
  const isOutOfCharges = hasChargeData && remaining === 0;
  const isDisabled = isOnCooldown || (isOutOfCharges && !isActive) || !!buffsLocked;

  useEffect(() => {
    return () => {
      if (longPressTimer.current) clearTimeout(longPressTimer.current);
      if (autoHideTimer.current) clearTimeout(autoHideTimer.current);
    };
  }, []);

  useEffect(() => {
    if (buffsLocked) {
      setShowTooltip(false);
      setShowRefillConfirm(false);
    }
  }, [buffsLocked]);

  const openTooltip = (): void => {
    setShowTooltip(true);
    if (autoHideTimer.current) clearTimeout(autoHideTimer.current);
    autoHideTimer.current = setTimeout(() => setShowTooltip(false), TOOLTIP_AUTO_HIDE_MS);
  };

  const closeTooltip = (): void => {
    setShowTooltip(false);
    if (autoHideTimer.current) clearTimeout(autoHideTimer.current);
  };

  const handleTouchStart = (): void => {
    if (buffsLocked) return;
    didLongPress.current = false;
    longPressTimer.current = setTimeout(() => {
      didLongPress.current = true;
      openTooltip();
    }, LONG_PRESS_MS);
  };

  const handleTouchEnd = (): void => {
    if (longPressTimer.current) {
      clearTimeout(longPressTimer.current);
      longPressTimer.current = null;
    }
  };

  const handleClick = (): void => {
    if (buffsLocked) return;
    if (didLongPress.current) {
      didLongPress.current = false;
      return;
    }
    setPressed(true);
    window.setTimeout(() => setPressed(false), 140);

    // When out of charges, show refill confirmation instead of doing nothing
    if (isOutOfCharges && !isOnCooldown && !isActive) {
      setShowRefillConfirm(true);
      return;
    }

    if (isDisabled) return;
    onActivate();
  };

  const dimmedFaceOpacity = buffsLocked
    ? 0.4
    : isDisabled
      ? (isOutOfCharges && !isOnCooldown ? 0.3 : 0.55)
      : 1;

  const hitStyle: CSSProperties = {
    position: 'relative',
    width: 44,
    height: 50,
    padding: 0,
    border: 'none',
    background: 'transparent',
    pointerEvents: buffsLocked ? 'none' : 'auto',
    cursor: buffsLocked || isDisabled ? 'not-allowed' : 'pointer',
    transform: pressed ? 'scale(0.94)' : 'scale(1)',
    transition: 'transform 80ms ease',
  };

  const activatorFaceStyle: CSSProperties = {
    ...buttonBase,
    position: 'absolute',
    inset: 0,
    width: '100%',
    height: '100%',
    borderRadius: 10,
    borderColor: isActive ? meta.color : pressed ? '#fff' : 'rgba(255,255,255,0.2)',
    boxShadow: isActive
      ? `0 0 12px ${meta.color}`
      : pressed
        ? `0 0 10px rgba(255,255,255,0.5), inset 0 0 12px ${meta.color}66`
        : 'none',
    opacity: dimmedFaceOpacity,
    transition: 'opacity 150ms ease, box-shadow 80ms ease, border-color 80ms ease',
    pointerEvents: 'none',
  };

  return (
    <button
      type="button"
      style={hitStyle}
      onClick={handleClick}
      onTouchStart={handleTouchStart}
      onTouchEnd={handleTouchEnd}
      onTouchCancel={handleTouchEnd}
      onMouseEnter={buffsLocked ? undefined : openTooltip}
      onMouseLeave={buffsLocked ? undefined : closeTooltip}
      aria-disabled={isDisabled}
      aria-label={`${meta.label}: ${meta.desc}`}
    >
      {/* Dim only the activator (chrome + icon); tooltip is a sibling so it stays full opacity. */}
      <div style={activatorFaceStyle}>
        {/* Inner wrapper clips cooldown overlay to button bounds */}
        <div
          style={{
            position: 'absolute',
            inset: 0,
            overflow: 'hidden',
            borderRadius: 8,
          }}
        >
          <RadialCooldown progress={cooldownProgress} />
        </div>
        <span style={{ fontSize: 18, lineHeight: 1, position: 'relative' }}>{meta.icon}</span>
        <span style={{ fontSize: 8, color: '#ccc', marginTop: 1, position: 'relative' }}>{meta.label}</span>
        {isActive && !isOnCooldown && (
          <span
            style={{
              position: 'absolute',
              bottom: 2,
              fontSize: 9,
              fontWeight: 700,
              color: meta.color,
              textShadow: '0 1px 2px rgba(0,0,0,0.9)',
            }}
          >
            {Math.ceil(remainingEffectMs / 1000)}s
          </span>
        )}
        {isOnCooldown && (
          <span
            style={{
              position: 'absolute',
              fontSize: 11,
              fontWeight: 700,
              color: '#fff',
              textShadow: '0 1px 2px rgba(0,0,0,0.8)',
            }}
          >
            {Math.ceil(buff.cooldownRemainingMs / 1000)}s
          </span>
        )}

        {/* Charge badge */}
        {hasChargeData && (
          <span
            style={{
              ...chargeBadgeBase,
              backgroundColor: isOutOfCharges ? '#aa2222' : 'rgba(30, 90, 180, 0.9)',
              color: isOutOfCharges ? '#ffaaaa' : '#fff',
            }}
          >
            {remaining}
          </span>
        )}
      </div>

      {showTooltip && (
        <div style={tooltipStyle}>
          <div style={{ color: meta.color, fontWeight: 700, marginBottom: 2 }}>{meta.label}</div>
          <div style={{ color: '#ddd', fontWeight: 400 }}>{meta.desc}</div>
          {cdSec > 0 && <div style={{ color: '#999', fontSize: 10, marginTop: 2 }}>CD: {cdSec}s</div>}
          {hasChargeData && (
            <div
              style={{
                fontSize: 10,
                marginTop: 3,
                color: isOutOfCharges ? '#ff8844' : '#aaccff',
              }}
            >
              {tr.charges}: {remaining}/{maxCharges}
            </div>
          )}
          {isOutOfCharges && charge?.periodEnd && (
            <div style={{ fontSize: 10, marginTop: 1, color: '#ff6644' }}>
              {tr.refillsAt} {formatTimeHHMM(charge.periodEnd)}
            </div>
          )}
          {SHOW_BUFF_REFILL_BUTTON_IN_TOOLTIP && isOutOfCharges && onRefill && (
            <button
              type="button"
              onClick={(e) => {
                e.stopPropagation();
                setShowRefillConfirm(true);
                closeTooltip();
              }}
              style={{
                marginTop: 4,
                padding: '3px 10px',
                fontSize: 10,
                fontWeight: 700,
                color: '#fff',
                backgroundColor: 'rgba(100, 180, 60, 0.85)',
                border: '1px solid rgba(100, 180, 60, 0.6)',
                borderRadius: 4,
                cursor: 'pointer',
                pointerEvents: 'auto',
              }}
            >
              {tr.refill}
            </button>
          )}
          <div style={tooltipArrow} />
        </div>
      )}

      {/* Refill confirmation popup */}
      {showRefillConfirm && (
        <div
          style={{
            position: 'absolute',
            bottom: '115%',
            left: '50%',
            transform: 'translateX(-50%)',
            padding: '8px 12px',
            borderRadius: 8,
            backgroundColor: 'rgba(10, 10, 20, 0.95)',
            border: '1px solid rgba(100, 180, 60, 0.4)',
            color: '#eee',
            fontSize: 11,
            fontWeight: 600,
            whiteSpace: 'nowrap',
            zIndex: 110,
            textAlign: 'center',
            boxShadow: '0 4px 16px rgba(0,0,0,0.6)',
          }}
        >
          <div style={{ marginBottom: 6 }}>
            {t(tr.refillQuestion, { label: meta.label })}
          </div>
          <div style={{ fontSize: 10, color: '#aaa', marginBottom: 8 }}>
            {buff.type === BuffType.Resurrection ? '150\u20BD' : '50\u20BD'}
          </div>
          <div style={{ display: 'flex', gap: 6, justifyContent: 'center' }}>
            <button
              type="button"
              onClick={(e) => {
                e.stopPropagation();
                setShowRefillConfirm(false);
                onRefill?.(buff.type);
              }}
              style={{
                padding: '4px 12px',
                fontSize: 10,
                fontWeight: 700,
                color: '#fff',
                backgroundColor: 'rgba(100, 180, 60, 0.85)',
                border: 'none',
                borderRadius: 4,
                cursor: 'pointer',
              }}
            >
              {tr.refill}
            </button>
            <button
              type="button"
              onClick={(e) => {
                e.stopPropagation();
                setShowRefillConfirm(false);
              }}
              style={{
                padding: '4px 12px',
                fontSize: 10,
                fontWeight: 700,
                color: '#aaa',
                backgroundColor: 'rgba(255,255,255,0.08)',
                border: 'none',
                borderRadius: 4,
                cursor: 'pointer',
              }}
            >
              {tr.cancel}
            </button>
          </div>
        </div>
      )}
    </button>
  );
}

// ---- Buff Bar ----

const barStyle: CSSProperties = {
  display: 'flex',
  gap: 4,
  justifyContent: 'center',
  flexWrap: 'wrap',
  padding: '6px 0',
};

/** All buff types that should always be visible as buttons */
const ALL_BUFF_TYPES: BuffType[] = [
  BuffType.Heal, BuffType.Rage, BuffType.Shield,
  BuffType.Rush, BuffType.PowerPotion, BuffType.WarCry,
  BuffType.Luck,
];

function getBuffEntry(
  type: BuffType,
  activeBuffs: ActiveBuff[],
  cooldownEndsAt: Partial<Record<BuffType, number>>,
  nowMs: number,
): ActiveBuff {
  const active = activeBuffs.find((b) => b.type === type);
  const cdEnd = cooldownEndsAt[type];
  const cdRem = cdEnd != null ? Math.max(0, cdEnd - nowMs) : 0;
  const cdFull = active?.cooldownMs || BUFF_COOLDOWN_MS[type];

  if (active) {
    const exp = active.expiresAtMs;
    const remainingMs = exp != null ? Math.max(0, exp - nowMs) : active.remainingMs;
    return {
      ...active,
      remainingMs,
      cooldownMs: active.cooldownMs || cdFull,
      cooldownRemainingMs: cdRem,
    };
  }

  return {
    type,
    remainingMs: 0,
    durationMs: 0,
    cooldownMs: cdFull,
    cooldownRemainingMs: cdRem,
  };
}

export function BuffBar({
  buffs,
  cooldownEndsAt,
  buffCharges,
  subscriptionActive,
  buffsLocked,
  nowMs,
  onActivate,
  onHeroUpdated,
}: BuffBarProps) {
  const handleActivate = useCallback(
    (type: BuffType) => () => onActivate(type),
    [onActivate],
  );

  const handleRefill = useCallback(
    (type: BuffType) => {
      const telegramId = getTelegramUserId() ?? undefined;
      purchaseBuffRefill(type, telegramId)
        .then((hero) => {
          onHeroUpdated?.(hero);
        })
        .catch((err) => {
          console.warn('[BuffBar] purchaseBuffRefill failed:', err);
        });
    },
    [onHeroUpdated],
  );

  return (
    <div style={barStyle}>
      {ALL_BUFF_TYPES.map((type) => {
        const buff = getBuffEntry(type, buffs, cooldownEndsAt, nowMs);
        const charge = buffCharges[type];
        const maxCharges = buffMaxChargesForHero(type, subscriptionActive);
        return (
          <BuffButton
            key={type}
            buff={buff}
            charge={charge}
            maxCharges={maxCharges}
            onActivate={handleActivate(type)}
            onRefill={handleRefill}
            nowMs={nowMs}
            buffsLocked={buffsLocked}
          />
        );
      })}
    </div>
  );
}
