import {
  EmbedBuilder,
  ButtonBuilder,
  ButtonStyle,
  ActionRowBuilder,
  TextChannel,
  GuildMember,
} from "discord.js";
import { PollState, VoteEntry, Nation, TGSlot } from "../types";
import { cfg } from "./config";
import { getEmoji, getClassEmoji, getNationEmoji } from "./emojis";
import { getActiveCharacter } from "./characters";
import { resolveNation } from "./nations";
import { getEntry, getBringer } from "./wrank";
import { nowFormatted } from "./messages";

// ─── Poll state ───────────────────────────────────────────────────────────────
export const polls: Map<number, PollState> = new Map();

const publicOverrides:    Map<string, { yes?: string; no?: string }> = new Map();
const ephemeralOverrides: Map<string, { yes?: string; no?: string }> = new Map();

export function setPublicOverride(userId: string, voteType: "yes" | "no", message: string): void {
  const e = publicOverrides.get(userId) ?? {};
  e[voteType] = message;
  publicOverrides.set(userId, e);
}
export function clearPublicOverride(userId: string, voteType?: "yes" | "no"): void {
  if (!voteType) { publicOverrides.delete(userId); return; }
  const e = publicOverrides.get(userId);
  if (e) delete e[voteType];
}
export function setEphemeralOverride(userId: string, voteType: "yes" | "no", message: string): void {
  const e = ephemeralOverrides.get(userId) ?? {};
  e[voteType] = message;
  ephemeralOverrides.set(userId, e);
}
export function clearEphemeralOverride(userId: string, voteType?: "yes" | "no"): void {
  if (!voteType) { ephemeralOverrides.delete(userId); return; }
  const e = ephemeralOverrides.get(userId);
  if (e) delete e[voteType];
}
export function getPublicOverride(userId: string, voteType: "yes" | "no"): string | undefined {
  return publicOverrides.get(userId)?.[voteType];
}
export function getEphemeralOverride(userId: string, voteType: "yes" | "no"): string | undefined {
  return ephemeralOverrides.get(userId)?.[voteType];
}
export function resetPollOverrides(): void {
  publicOverrides.clear();
  ephemeralOverrides.clear();
}

// ─── Character display ────────────────────────────────────────────────────────
function formatCharRow(entry: VoteEntry, showNationEmoji = false): string {
  const format     = cfg("charDisplayFormat");
  const nation     = entry.characterNation;
  const wRankEntry = entry.usermapKey ? getEntry(entry.usermapKey, nation ?? "Capella") : null;

  let wrank = "";
  if (wRankEntry) {
    const goal    = cfg("wRankGoal");
    const isDone  = wRankEntry.tgCount >= goal;
    const rank    = wRankEntry.currentRank;
    const prev    = wRankEntry.previousRank;
    const delta   = prev !== undefined ? rank - prev : 0;
    // W.Rank emoji with text fallback
    const rankEmojiKey = isDone ? `wrank_${rank}_gold` : `wrank_${rank}`;
    const rankStr      = getEmoji(rankEmojiKey) || (isDone ? `🟡${rank}` : `${rank}`);

    // Delta arrows with text fallback
    let deltaStr = "";
    if (delta < 0)      deltaStr = ` (${getEmoji("wrank_up")      || "↑"}${Math.abs(delta)})`;
    else if (delta > 0) deltaStr = ` (${getEmoji("wrank_down")    || "↓"}${delta})`;
    else if (prev !== undefined) deltaStr = ` (${getEmoji("wrank_neutral") || "·"}0)`;

    wrank = `${rankStr}${deltaStr}`;
  }

  const classStr = entry.characterClass
    ? (getClassEmoji(entry.characterClass) || entry.characterClass)
    : "";

  const levelStr = entry.characterLevel && cfg("showLevelInMessages" as any)
    ? `${entry.characterLevel}`
    : "";

  let row = format
    .replace("{wrank}", wrank)
    .replace("{class}",  classStr)
    .replace("{level}",  levelStr)
    .replace("{name}",   entry.characterName ?? entry.displayName)
    .replace(/\s+/g, " ")
    .trim();

  // Bringer title — independent of W.Rank so override always shows
  if (nation && entry.usermapKey) {
    const bringer = getBringer(nation);
    if (bringer && bringer === entry.usermapKey) {
      const emoji = nation === "Capella"
        ? (getEmoji("luminous_bringer") || "🔆")
        : (getEmoji("storm_bringer")    || "⚡");
      const title = nation === "Capella" ? "Luminous Bringer" : "Storm Bringer";
      row += ` · ${emoji} **${title}**`;
    }
  }

  if (showNationEmoji && nation) row = `${getNationEmoji(nation)} ${row}`;

  return row;
}

// ─── Embed building ───────────────────────────────────────────────────────────
export function buildEmbed(state: PollState, overrideLockMsg?: string): EmbedBuilder {
  const yesByNation   = { Capella: [] as VoteEntry[], Procyon: [] as VoteEntry[] };
  const noVoters: VoteEntry[] = [];
  const allMessages: { entry: VoteEntry; voteType: "yes" | "no" }[] = [];
  const showNoInline  = (cfg as any)("showNoInNationField") ?? false;

  for (const entry of state.yes.values()) {
    const nation = entry.characterNation ?? "Capella";
    yesByNation[nation].push(entry);
    allMessages.push({ entry, voteType: "yes" });
  }
  for (const entry of state.no.values()) {
    noVoters.push(entry);
    allMessages.push({ entry, voteType: "no" });
  }

  const capellaEmoji = getEmoji("capella");
  const procyonEmoji = getEmoji("procyon");

  const formatNationField = (nation: Nation): string => {
    const yesEntries = yesByNation[nation];
    const noEntries  = showNoInline
      ? noVoters.filter((e) => e.characterNation === nation)
      : [];
    const lines = [
      ...yesEntries.map((e) => formatCharRow(e)),
      ...noEntries.map((e) => `❌ ${formatCharRow(e)}`),
    ];
    return lines.length > 0 ? lines.join("\n") : "—";
  };

  const formatMessages = (): string => {
    if (allMessages.length === 0) return "";
    return allMessages
      .map((m) => {
        const name   = m.entry.characterName ?? m.entry.displayName;
        const prefix = m.voteType === "no" ? "✗ " : "✓ ";
        const msg    = m.entry.publicMessage ? ` — ${m.entry.publicMessage}` : "";
        return `${prefix}${name} · ${m.entry.votedAt}${msg}`;
      })
      .join("\n");
  };

  const locked    = state.locked;
  const confirmed = state.confirmed;

  const color =
    confirmed === "yes" ? 0x57f287 :
    confirmed === "no"  ? 0xed4245 :
    locked              ? 0x888888 :
                          0xe8a317;

  // Title with nation + no counts (hidden when confirmed or locked)
  const counts = !locked && confirmed === null
    ? `  ${capellaEmoji} ${yesByNation.Capella.length}  ${procyonEmoji} ${yesByNation.Procyon.length}`
    : "";
  const statusSuffix =
    locked              ? " 🔒" :
    confirmed === "yes" ? " ✅" :
    confirmed === "no"  ? " ❌" : "";

  const title = `⚔️ TG — ${state.slot}:00${counts}${statusSuffix}`;

  const embed = new EmbedBuilder()
    .setTitle(title)
    .setColor(color)
    .addFields(
      { name: `${capellaEmoji} Capella (${yesByNation.Capella.length})`, value: formatNationField("Capella"), inline: false },
      { name: "\u200b", value: "\u200b", inline: false },
      { name: `${procyonEmoji} Procyon (${yesByNation.Procyon.length})`, value: formatNationField("Procyon"), inline: false },
    )
    .setTimestamp();

  const msgSection = formatMessages();
  if (msgSection) {
    embed.addFields({ name: "\u200b", value: msgSection, inline: false });
  }

  let footer: string;
  if (confirmed === "yes")     footer = cfg("confirmYesMessage");
  else if (confirmed === "no") footer = cfg("confirmNoMessage");
  else if (locked)             footer = overrideLockMsg ?? cfg("lockMessage");
  else                         footer = `❌ ${noVoters.length} • Vote updates live • Anyone can vote • /tg switch to change character`;
  embed.setFooter({ text: footer });

  return embed;
}

export function buildButtons(disabled: boolean): ActionRowBuilder<ButtonBuilder> {
  const yesBtn = new ButtonBuilder()
    .setCustomId("tg_yes").setLabel("✅  Yes").setStyle(ButtonStyle.Success).setDisabled(disabled);
  const noBtn = new ButtonBuilder()
    .setCustomId("tg_no").setLabel("❌  No").setStyle(ButtonStyle.Danger).setDisabled(disabled);
  return new ActionRowBuilder<ButtonBuilder>().addComponents(yesBtn, noBtn);
}

export async function updatePollMessage(channel: TextChannel, slot: number, overrideLockMsg?: string): Promise<void> {
  const state = polls.get(slot);
  if (!state?.messageId) return;
  try {
    const msg      = await channel.messages.fetch(state.messageId);
    const disabled = state.locked || state.confirmed !== null;
    await msg.edit({ embeds: [buildEmbed(state, overrideLockMsg)], components: [buildButtons(disabled)] });
  } catch (err) {
    console.error("Failed to update poll message:", err);
  }
}

export async function postPoll(channel: TextChannel, slot: TGSlot): Promise<void> {
  resetPollOverrides();
  const state: PollState = {
    messageId: null, slot: slot.tgHour,
    yes: new Map(), no: new Map(),
    locked: false, confirmed: null,
  };
  polls.set(slot.tgHour, state);
  const msg = await channel.send({ embeds: [buildEmbed(state)], components: [buildButtons(false)] });
  state.messageId = msg.id;
  console.log(`[${new Date().toISOString()}] Poll posted for ${slot.tgHour}:00.`);
}

export function createVoteEntry(
  userId: string,
  member: GuildMember,
  usermapKey: string | null,
  discordUsername: string
): Omit<VoteEntry, "votedAt" | "previousYesAt" | "previousNoAt" | "publicMessage"> {
  const serverNickname = member.nickname ?? null;
  const globalNickname = member.user.globalName ?? null;
  const displayName    = serverNickname ?? globalNickname ?? discordUsername;
  const nation         = resolveNation(member, usermapKey);
  const char           = usermapKey ? getActiveCharacter(usermapKey) : null;
  return {
    usermapKey:       usermapKey ?? (undefined as any),
    displayName,
    characterName:    char?.name,
    characterClass:   char?.class,
    characterLevel:   char?.level,
    characterNation:  nation ?? undefined,
  };
}