interface DiscordEmbed {
  title?: string;
  description?: string;
  color?: number;
  footer?: { text: string };
}

interface DiscordWebhookPayload {
  content?: string;
  embeds?: DiscordEmbed[];
}

export async function sendDiscordWebhook(
  webhookUrl: string,
  payload: DiscordWebhookPayload
): Promise<void> {
  const response = await fetch(webhookUrl, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(payload),
  });

  if (!response.ok) {
    const text = await response.text().catch(() => "");
    throw new Error(`Discord webhook failed: ${response.status} ${text}`);
  }
}

/** Escape characters that trigger Discord markdown formatting. */
function escapeMarkdown(text: string): string {
  return text.replace(/[_*~`|\\]/g, "\\$&");
}

export interface StandingEntry {
  teamId: string;
  teamName: string;
  username?: string;
  totalPoints: number;
  rank: number;
}

export interface ScoredMatch {
  winnerName: string;
  loserName: string;
  winnerUsername?: string;
  loserUsername?: string;
}

export async function sendStandingsUpdateNotification({
  webhookUrl,
  seasonName,
  standings,
  previousStandings,
  previousRanks,
  sportName,
  eventName,
  scoredMatches,
}: {
  webhookUrl: string;
  seasonName: string;
  standings: StandingEntry[];
  previousStandings: Map<string, number>;
  previousRanks?: Map<string, number>;
  sportName?: string;
  eventName?: string;
  scoredMatches?: ScoredMatch[];
}): Promise<void> {
  const sections: string[] = [];

  // Header: "Sport Name — Event Name"
  if (sportName || eventName) {
    const parts = [sportName, eventName].filter(Boolean);
    sections.push(`**${parts.join(" — ")}**`);
  }

  // Scored matches section — only show matches where at least one manager
  // (fantasy team owner) scored Brackt points or had a team eliminated.
  const relevantMatches = scoredMatches?.filter(
    (m) => m.winnerUsername !== undefined || m.loserUsername !== undefined
  );
  if (relevantMatches && relevantMatches.length > 0) {
    sections.push("\n**Scored Matches**");
    for (const match of relevantMatches) {
      const winnerLabel = match.winnerUsername
        ? `${escapeMarkdown(match.winnerName)} (${escapeMarkdown(match.winnerUsername)})`
        : escapeMarkdown(match.winnerName);
      const loserLabel = match.loserUsername
        ? `${escapeMarkdown(match.loserName)} (${escapeMarkdown(match.loserUsername)})`
        : escapeMarkdown(match.loserName);
      sections.push(`• **${winnerLabel}** def. ${loserLabel}`);
    }
  }

  // Standings changes section — show teams whose points or rank changed.
  const changedTeams = standings.filter((s) => {
    const prevPoints = previousStandings.get(s.teamId);
    const pointsChanged = prevPoints !== undefined && prevPoints !== s.totalPoints;
    const prevRank = previousRanks?.get(s.teamId);
    const rankChanged = prevRank !== undefined && prevRank !== s.rank;
    return pointsChanged || rankChanged;
  });

  if (changedTeams.length > 0) {
    sections.push("\n**Standings Changes**");
    for (const s of changedTeams) {
      const prevPoints = previousStandings.get(s.teamId);
      let pointDelta = "";
      if (prevPoints !== undefined && prevPoints !== s.totalPoints) {
        const diff = Math.round(s.totalPoints - prevPoints);
        const sign = diff > 0 ? "+" : "";
        pointDelta = ` **(${sign}${diff} pts)**`;
      }

      let rankDelta = "";
      if (previousRanks) {
        const prevRank = previousRanks.get(s.teamId);
        if (prevRank !== undefined && prevRank !== s.rank) {
          const moved = prevRank - s.rank; // positive = moved up
          rankDelta = moved > 0 ? ` ↑${moved}` : ` ↓${Math.abs(moved)}`;
        }
      }

      const escapedName = escapeMarkdown(s.teamName);
      const escapedUsername = s.username ? escapeMarkdown(s.username) : undefined;
      const label = escapedUsername ? `${escapedName} (${escapedUsername})` : escapedName;
      sections.push(`${s.rank}. ${label} — ${Math.round(s.totalPoints)} pts${pointDelta}${rankDelta}`);
    }
  }

  const MAX_DESCRIPTION = 4096;
  let description = sections.join("\n");
  if (description.length > MAX_DESCRIPTION) {
    description = description.slice(0, MAX_DESCRIPTION - 3) + "...";
  }

  await sendDiscordWebhook(webhookUrl, {
    embeds: [
      {
        title: `📊 Standings Update — ${seasonName}`,
        description,
        color: 0x5865f2, // Discord blurple
        footer: { text: "brackt.com" },
      },
    ],
  });
}
