import { BuffType, DebuffType, type ActiveBuff, type ActiveDebuff } from '../game/types';

/** Mirrors backend/internal/model/buff.go CooldownDuration */
export const BUFF_COOLDOWN_MS: Record<BuffType, number> = {
  [BuffType.Rush]: 15 * 60_000,       // 15 min
  [BuffType.Rage]: 10 * 60_000,       // 10 min
  [BuffType.Shield]: 12 * 60_000,     // 12 min
  [BuffType.Luck]: 2 * 60 * 60_000,   // 2 hours
  [BuffType.Resurrection]: 30 * 60_000, // 30 min
  [BuffType.Heal]: 5 * 60_000,        // 5 min
  [BuffType.PowerPotion]: 20 * 60_000, // 20 min
  [BuffType.WarCry]: 10 * 60_000,     // 10 min
};

/** Max buff charges per 24h period (mirrors backend BuffFreeChargesPerType). */
export const BUFF_MAX_CHARGES: Record<BuffType, number> = {
  [BuffType.Rush]: 3,
  [BuffType.Rage]: 2,
  [BuffType.Shield]: 2,
  [BuffType.Luck]: 1,
  [BuffType.Resurrection]: 1,
  [BuffType.Heal]: 3,
  [BuffType.PowerPotion]: 1,
  [BuffType.WarCry]: 2,
};

/** Subscriber caps (mirrors backend BuffSubscriberChargesPerType, ×2). */
export const BUFF_MAX_CHARGES_SUBSCRIBER: Record<BuffType, number> = {
  [BuffType.Rush]: 6,
  [BuffType.Rage]: 4,
  [BuffType.Shield]: 4,
  [BuffType.Luck]: 2,
  [BuffType.Resurrection]: 2,
  [BuffType.Heal]: 6,
  [BuffType.PowerPotion]: 2,
  [BuffType.WarCry]: 4,
};

export function buffMaxChargesForHero(type: BuffType, subscriptionActive: boolean | undefined): number {
  if (subscriptionActive) {
    return BUFF_MAX_CHARGES_SUBSCRIBER[type];
  }
  return BUFF_MAX_CHARGES[type];
}

/** Mirrors backend/internal/model/buff.go Duration */
export const BUFF_DURATION_MS: Record<BuffType, number> = {
  [BuffType.Rush]: 5 * 60_000,        // 5 min
  [BuffType.Rage]: 3 * 60_000,        // 3 min
  [BuffType.Shield]: 5 * 60_000,      // 5 min
  [BuffType.Luck]: 30 * 60_000,       // 30 min
  [BuffType.Resurrection]: 10 * 60_000, // 10 min
  [BuffType.Heal]: 1_000,             // instant
  [BuffType.PowerPotion]: 5 * 60_000,  // 5 min
  [BuffType.WarCry]: 3 * 60_000,      // 3 min
};

// ---- Server row shapes (Go JSON) ----

export interface ServerBuffRow {
  id?: number;
  type: string;
  name?: string;
  duration?: number;
  magnitude?: number;
  cooldownDuration?: number;
}

export interface ServerActiveBuffRow {
  buff: ServerBuffRow;
  appliedAt: string;
  expiresAt: string;
}

export interface ServerDebuffRow {
  id?: number;
  type: string;
  name?: string;
  duration?: number;
  magnitude?: number;
}

export interface ServerActiveDebuffRow {
  debuff: ServerDebuffRow;
  appliedAt: string;
  expiresAt: string;
}

function durationToMs(raw: unknown): number {
  if (typeof raw === 'number' && Number.isFinite(raw)) {
    return Math.round(raw / 1_000_000);
  }
  return 0;
}

function isBuffType(s: string): s is BuffType {
  return Object.values(BuffType).includes(s as BuffType);
}

function isDebuffType(s: string): s is DebuffType {
  return Object.values(DebuffType).includes(s as DebuffType);
}

/** Parse one active buff row from the API into client ActiveBuff (with expiresAtMs for UI ticking). */
export function mapServerActiveBuff(row: ServerActiveBuffRow, nowMs: number): ActiveBuff | null {
  const t = row.buff?.type;
  if (!t || !isBuffType(t)) return null;
  const exp = Date.parse(row.expiresAt);
  const app = Date.parse(row.appliedAt);
  if (!Number.isFinite(exp) || !Number.isFinite(app)) return null;

  const cooldownMs = durationToMs(row.buff.cooldownDuration) || BUFF_COOLDOWN_MS[t];
  const durationMs = Math.max(0, exp - app);

  return {
    type: t,
    remainingMs: Math.max(0, exp - nowMs),
    durationMs,
    cooldownMs,
    cooldownRemainingMs: 0,
    expiresAtMs: exp,
  };
}

export function mapServerActiveDebuff(row: ServerActiveDebuffRow, nowMs: number): ActiveDebuff | null {
  const t = row.debuff?.type;
  if (!t || !isDebuffType(t)) return null;
  const exp = Date.parse(row.expiresAt);
  const app = Date.parse(row.appliedAt);
  if (!Number.isFinite(exp) || !Number.isFinite(app)) return null;

  const durationMs = Math.max(0, exp - app);
  return {
    type: t,
    remainingMs: Math.max(0, exp - nowMs),
    durationMs,
    expiresAtMs: exp,
  };
}

export function mapHeroBuffsFromServer(rows: ServerActiveBuffRow[] | undefined, nowMs: number): ActiveBuff[] {
  if (!rows?.length) return [];
  const out: ActiveBuff[] = [];
  for (const row of rows) {
    const b = mapServerActiveBuff(row, nowMs);
    if (b && b.remainingMs > 0) out.push(b);
  }
  return out;
}

export function mapHeroDebuffsFromServer(rows: ServerActiveDebuffRow[] | undefined, nowMs: number): ActiveDebuff[] {
  if (!rows?.length) return [];
  const out: ActiveDebuff[] = [];
  for (const row of rows) {
    const d = mapServerActiveDebuff(row, nowMs);
    if (d && d.remainingMs > 0) out.push(d);
  }
  return out;
}

export function cooldownMsFromActivateBuffRow(row: ServerActiveBuffRow): number {
  const t = row.buff?.type;
  const fromApi = durationToMs(row.buff?.cooldownDuration);
  if (fromApi > 0) return fromApi;
  if (t && isBuffType(t)) return BUFF_COOLDOWN_MS[t];
  return 45_000;
}
