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_META } 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;
  nowMs: number;
  onActivate: (type: BuffType) => void;
  /** Called when a buff refill purchase returns an updated hero */
  onHeroUpdated?: (hero: HeroResponse) => void;
}

interface BuffButtonProps {
  buff: ActiveBuff;
  meta: { icon: string; label: string; color: string; desc: string };
  charge: BuffChargeState | undefined;
  maxCharges: number;
  onActivate: () => void;
  onRefill?: (type: BuffType) => void;
  nowMs: number;
}

// ---- Tooltip ----

const LONG_PRESS_MS = 400;
const TOOLTIP_AUTO_HIDE_MS = 2500;

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, meta, charge, maxCharges, onActivate, onRefill, nowMs }: BuffButtonProps) {
  const tr = useT();
  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);

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

  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 => {
    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 (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 style: CSSProperties = {
    ...buttonBase,
    width: 44,
    height: 50,
    borderRadius: 10,
    borderColor: isActive ? meta.color : pressed ? '#fff' : 'rgba(255,255,255,0.2)',
    opacity: isDisabled ? (isOutOfCharges && !isOnCooldown ? 0.3 : 0.55) : 1,
    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',
    transform: pressed ? 'scale(0.94)' : 'scale(1)',
    transition: 'transform 80ms ease, box-shadow 80ms ease, border-color 80ms ease, opacity 150ms ease',
    cursor: isDisabled ? 'not-allowed' : 'pointer',
  };

  return (
    <button
      type="button"
      style={style}
      onClick={handleClick}
      onTouchStart={handleTouchStart}
      onTouchEnd={handleTouchEnd}
      onTouchCancel={handleTouchEnd}
      onMouseEnter={openTooltip}
      onMouseLeave={closeTooltip}
      aria-disabled={isDisabled}
      aria-label={`${meta.label}: ${meta.desc}`}
    >
      {/* 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>
      )}

      {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>
          )}
          {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, 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 meta = BUFF_META[type];
        const charge = buffCharges[type];
        const maxCharges = buffMaxChargesForHero(type, subscriptionActive);
        return (
          <BuffButton
            key={type}
            buff={buff}
            meta={meta}
            charge={charge}
            maxCharges={maxCharges}
            onActivate={handleActivate(type)}
            onRefill={handleRefill}
            nowMs={nowMs}
          />
        );
      })}
    </div>
  );
}
