import {
  ButtonInteraction,
  StringSelectMenuBuilder,
  StringSelectMenuOptionBuilder,
  ActionRowBuilder,
  TextChannel
} from "discord.js";
import { cfg } from "@systems/config";
import { pollReplyAndDelete } from "../utils";
import { resolveUser } from "@systems/users";
import { resolveMessage, nowFormatted } from "@systems/messages";
import { resolveNation } from "@systems/nations";
import { polls, updatePollMessage, createVoteEntry, getPublicOverride, getEphemeralOverride } from "@systems/poll";
import { persist } from "@systems/pollPersistence"
import { showConflictEmbed } from "@systems/conflict";
import { getCharacters } from "@systems/characters";
import { getImpersonation } from "@systems/impersonate";
import { format } from "@format";
import { Character } from "@src/types";
import { modals } from "@handlers/modals";

const LOCK_AT = parseInt(process.env.LOCK_AT ?? "10");

const clickCounts = new Map<string, { yes: number; no: number }>();

// ─── Helpers ──────────────────────────────────────────────────────────────────

function isCharacterInPoll(
  state: ReturnType<typeof polls.get>,
  charName: string,
  excludeVoteId: string,
  excludeUserKey: string = ""
): { found: boolean; entryUserKey: string | null; borrowedFrom: string | undefined } {
  if (!state) return { found: false, entryUserKey: null, borrowedFrom: undefined };
  for (const [otherId, entry] of state.yes.entries()) {
    if (otherId !== excludeVoteId && entry.userKey !== excludeUserKey && entry.characterName === charName) {
      return { found: true, entryUserKey: entry.userKey ?? null, borrowedFrom: entry.borrowedFrom };
    }
  }
  return { found: false, entryUserKey: null, borrowedFrom: undefined };
}

function isCharacterOwner(userKey: string | null, charName: string): boolean {
  if (!userKey) return false;
  return getCharacters(userKey).some((c) => c.name === charName);
}

async function handleCharacterConflict(
  interaction: ButtonInteraction,
  userKey: string | null,
  char: Character,
  entryUserKey: string | null,
  clicks: { yes: number; no: number },
  votedYes: boolean
): Promise<boolean> {
  // Decrement click since we're blocking this vote
  if (votedYes) clicks.yes -= 1;
  else          clicks.no  -= 1;

  const isOwner = isCharacterOwner(userKey, char.name);

  if (isOwner && userKey) {
    const allChars    = getCharacters(userKey);
    const borrowedChar = allChars.find((c) => c.name === char.name);
    if (borrowedChar && entryUserKey) {
      await showConflictEmbed(interaction, userKey, entryUserKey, borrowedChar, allChars);
      return true;
    }
  }

  const slot  = [...polls.keys()][0];
  const slotHour = slot !== undefined ? polls.get(slot)?.slot : cfg("slots")[0]?.tgHour ?? 20;

  // await interaction.followUp({
  //   content: `❌ ${format.char(char)} is already scheduled for TG at ${slotHour}:00. Pick a different character.`,
  //   // content: `❌ **${char.name}** is already in the poll by another player. Switch to a different character first.`,
  //   ephemeral: true
  // });
  const { buildCharSelectButtons } = require("@systems/charSelect");
  const buttons = buildCharSelectButtons(userKey ?? "", {
    customIdPrefix:   `switch_after_reclaim:${userKey}`,
    excludeCharName:  char.name,
    appendToCustomId: ":yes",
  });
  await interaction.followUp({
    content:    `❌ ${format.char(char)} is already scheduled for TG at ${slotHour}:00. Pick a different character.`,
    components: buttons,
    ephemeral:  true,
  });
  return true;
}

// ─── Main button handler ──────────────────────────────────────────────────────

export async function handleButton(interaction: ButtonInteraction): Promise<void> {
  if (!["tg_yes", "tg_no"].includes(interaction.customId)) return;

  try {
    await interaction.deferUpdate();
  } catch {
    return;
  }

  const slot = [...polls.entries()].find(([, s]) => s.messageId === interaction.message.id)?.[0];
  if (slot === undefined) return;

  const state = polls.get(slot)!;
  if (state.locked || state.confirmed !== null) return;

  const userId   = interaction.user.id;
  const member   = interaction.guild!.members.cache.get(userId)
    ?? await interaction.guild!.members.fetch(userId);
  const user     = await resolveUser(member);
  const votedYes = interaction.customId === "tg_yes";
  const now      = nowFormatted();

  const impersonating  = getImpersonation(userId);
  const voteId         = impersonating ? `impersonated:${impersonating}` : userId;
  const lookupUsername = user.lookupUsername ?? user.discordUsername;

  // Nation check
  const nation = resolveNation(member, user.userKey);
  if (!nation) {
    const capella = format.nation("Capella");
    const procyon = format.nation("Procyon");
    await interaction.followUp({ content: `❌ You must be in ${capella} or ${procyon} to vote.`, ephemeral: true });
    return;
  }

  // Click tracking
  if (!clickCounts.has(voteId)) clickCounts.set(voteId, { yes: 0, no: 0 });
  const clicks = clickCounts.get(voteId)!;

  if (votedYes  && clicks.yes >= LOCK_AT) return;
  if (!votedYes && clicks.no  >= LOCK_AT) return;

  // Ignore same vote
  if (votedYes  && state.yes.has(voteId)) return;
  if (!votedYes && state.no.has(voteId))  return;

  // Increment click (may be decremented in conflict handler)
  if (votedYes) clicks.yes += 1;
  else          clicks.no  += 1;

  const clickCount = votedYes ? clicks.yes : clicks.no;

  // Resolve messages
  const publicMsg = getPublicOverride(voteId, votedYes ? "yes" : "no")
    ?? resolveMessage("public", votedYes ? "yes" : "no", clickCount, lookupUsername, user.serverNickname, user.globalNickname);

  const ephemeralMsg = getEphemeralOverride(voteId, votedYes ? "yes" : "no")
    ?? resolveMessage("ephemeral", votedYes ? "yes" : "no", clickCount, lookupUsername, user.serverNickname, user.globalNickname);

  const baseEntry = createVoteEntry(voteId, member, user.userKey, lookupUsername);

  // Character conflict check — applies to both Yes and No
  if (baseEntry.characterName) {
    const conflictChar = {
      name:   baseEntry.characterName!,
      class:  baseEntry.characterClass!,
      level:  baseEntry.characterLevel!,
      nation: baseEntry.characterNation!,
      active: false, // not needed for display
    };
    
    const { found, entryUserKey, borrowedFrom } = isCharacterInPoll(
      state, baseEntry.characterName, voteId, user.userKey ?? ""
    );
    if (found) {
      await handleCharacterConflict(
        interaction, user.userKey, conflictChar,
        entryUserKey, clicks, votedYes
      );
      return;
    }
  }

  // Register vote
  if (votedYes) {
    const previousNo = state.no.get(voteId);
    state.no.delete(voteId);
    state.yes.set(voteId, {
      ...baseEntry,
      discordId:     userId,
      votedAt:       now,
      previousNoAt:  previousNo?.votedAt,
      publicMessage: publicMsg ?? undefined,
    });
  } else {
    const previousYes = state.yes.get(voteId);
    state.yes.delete(voteId);
    state.no.set(voteId, {
      ...baseEntry,
      votedAt:        now,
      discordId:     userId,
      previousYesAt:  previousYes?.votedAt,
      publicMessage:  publicMsg ?? undefined,
    });
  }

  const locked = clickCount >= LOCK_AT;
  if (locked) state.locked = true;
  persist.save(polls);

  const lockedSuffix = locked ? "\n🔒 *You've been locked in.*" : "";
  const msgContent   = ephemeralMsg
    ? `${ephemeralMsg}${lockedSuffix}`
    : locked ? "🔒 You've been locked in." : null;
  await pollReplyAndDelete(interaction, msgContent);

  const channel = interaction.channel as TextChannel;
  await updatePollMessage(channel, slot);
}

export function resetClickCounts(): void {
  clickCounts.clear();
}


// ─── Score submission button handler ──────────────────────────────────────────────────────

export async function handleScoreSubmitButton(interaction: ButtonInteraction): Promise<void> {
  const member  = await interaction.guild!.members.fetch(interaction.user.id);
  const user    = await resolveUser(member);
  if (!user.userKey) {
    await interaction.reply({ content: "❌ You are not registered in the system.", ephemeral: true });
    return;
  }

  const slot  = [...polls.entries()].find(([, s]) => s.messageId === interaction.message.id)?.[0];
  const state = slot !== undefined ? polls.get(slot) : null;

  if (!state?.lockedYesKeys?.has(user.userKey)) {
    await interaction.reply({ content: "❌ You weren't in this TG.", ephemeral: true });
    return;
  }

  // Slot is known from the poll — go straight to modal, no select needed
  await interaction.showModal(modals.buildScoreModal(user.userKey, slot!));
}

// export async function handleScoreSubmitButton(interaction: ButtonInteraction): Promise<void> {
//   await interaction.deferReply({ ephemeral: true });
 
//   const member  = await interaction.guild!.members.fetch(interaction.user.id);
//   const user    = await resolveUser(member);
//   if (!user.userKey) {
//     await interaction.editReply("❌ You are not registered in the system.");
//     return;
//   }
 
//   // Find the poll this message belongs to
//   const slot  = [...polls.entries()].find(([, s]) => s.messageId === interaction.message.id)?.[0];
//   const state = slot !== undefined ? polls.get(slot) : null;
 
//   // Enforce: only players who were locked in at TG start can submit
//   if (!state?.lockedYesKeys?.has(user.userKey)) {
//     await interaction.editReply("❌ You weren't in this TG.");
//     return;
//   }
 
//   // Build slot selector — all valid slots, with the active TG pre-selected
//   const validSlots  = cfg("slots").map((s) => s.tgHour) as number[];
//   const activeSlot  = slot ?? cfg("slots").find((s) => s.active)?.tgHour ?? 20;
 
//   const select = new StringSelectMenuBuilder()
//     .setCustomId(`score_slot_select:${user.userKey}`)
//     .setPlaceholder("Select TG slot")
//     .addOptions(
//       validSlots.map((h) =>
//         new StringSelectMenuOptionBuilder()
//           .setLabel(`${String(h).padStart(2, "0")}:00 TG`)
//           .setValue(String(h))
//           .setDefault(h === activeSlot)
//       )
//     );
 
//   const row = new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(select);
 
//   await interaction.editReply({
//     content: "Which TG are you submitting for?",
//     components: [row],
//   });
// }