import { format } from "date-fns";
import type { AuditLogEntry } from "~/models/audit-log";

export const AUDIT_ACTION_LABELS: Record<string, string> = {
  league_settings_changed: "League Settings Changed",
  draft_settings_changed: "Draft Settings Changed",
  scoring_rules_changed: "Scoring Rules Changed",
  sports_changed: "Sports Changed",
  draft_order_set: "Draft Order Set",
  draft_order_randomized: "Draft Order Randomized",
  draft_started: "Draft Started",
  draft_paused: "Draft Paused",
  draft_resumed: "Draft Resumed",
  draft_reset: "Draft Reset",
  draft_rollback: "Draft Rolled Back",
  force_autopick: "Forced Auto-Pick",
  force_manual_pick: "Forced Manual Pick",
  draft_pick_changed: "Pick Replaced",
  time_bank_edited: "Time Bank Edited",
  brackt_resolved: "Brackt Resolved",
};

const SCORING_FIELD_LABELS: Record<string, string> = {
  pointsFor1st: "1st",
  pointsFor2nd: "2nd",
  pointsFor3rd: "3rd",
  pointsFor4th: "4th",
  pointsFor5th: "5th",
  pointsFor6th: "6th",
  pointsFor7th: "7th",
  pointsFor8th: "8th",
};

const DRAFT_FIELD_LABELS: Record<string, string> = {
  draftRounds: "Rounds",
  draftDateTime: "Draft date",
  draftInitialTime: "Initial time",
  draftIncrementTime: "Increment",
  draftTimerMode: "Timer mode",
};

const LEAGUE_FIELD_LABELS: Record<string, string> = {
  name: "Name",
  isPublicDraftBoard: "Public draft board",
  discordWebhookUrl: "Discord webhook",
};

function formatDuration(seconds: number): string {
  const m = Math.floor(seconds / 60);
  const s = seconds % 60;
  if (m === 0) return `${s}s`;
  if (s === 0) return `${m}m`;
  return `${m}m ${s}s`;
}

function formatDraftField(key: string, value: unknown): string {
  if (value === null || value === undefined) return "none";
  if (key === "draftInitialTime" || key === "draftIncrementTime") {
    return formatDuration(Number(value));
  }
  if (key === "draftDateTime") {
    return format(new Date(value as string), "MMM d, yyyy h:mm a");
  }
  if (key === "draftTimerMode") {
    return value === "chess_clock" ? "Chess clock" : "Standard";
  }
  // draftRounds and any other numeric fields render as plain numbers
  return String(value);
}

function formatLeagueField(key: string, value: unknown): string {
  if (value === null || value === undefined || value === "") return "none";
  if (key === "isPublicDraftBoard") return value ? "Yes" : "No";
  if (key === "discordWebhookUrl") return "set";
  return String(value);
}

function diffLines(
  fields: string[],
  prev: Record<string, unknown>,
  next: Record<string, unknown>,
  labels: Record<string, string>,
  formatter: (key: string, value: unknown) => string
): string {
  if (fields.length === 0) return "";
  return fields
    .map((f) => {
      const label = labels[f] ?? f;
      const from = prev[f];
      const to = next[f];
      // `from` is undefined when the log entry predates the addition of previousValues —
      // in that case just show the new value without an arrow.
      if (from !== undefined) {
        return `${label}: ${formatter(f, from)} → ${formatter(f, to)}`;
      }
      return `${label}: ${formatter(f, to)}`;
    })
    .join(", ");
}

function truncateList(names: string[], max = 3): string {
  if (names.length <= max) return names.join(", ");
  return `${names.slice(0, max).join(", ")} +${names.length - max} more`;
}

function formatSeconds(seconds: number): string {
  const m = Math.floor(Math.abs(seconds) / 60);
  const s = Math.abs(seconds) % 60;
  const sign = seconds < 0 ? "-" : "+";
  if (m === 0) return `${sign}${s}s`;
  return `${sign}${m}m ${s}s`;
}

function formatTimeRemaining(seconds: number): string {
  const m = Math.floor(seconds / 60);
  const s = seconds % 60;
  return `${m}:${String(s).padStart(2, "0")}`;
}

/**
 * Returns a concise human-readable summary of an audit log entry.
 * Shared between the league home page summary widget and the full audit log page.
 */
export function formatAuditDetail(entry: AuditLogEntry): string {
  const d = (entry.details ?? {}) as Record<string, unknown>;

  switch (entry.action) {
    case "draft_rollback":
      return `Rolled back to pick #${d.rolledBackToPickNumber}`;

    case "time_bank_edited": {
      const adj = Number(d.adjustment ?? 0);
      const remaining = Number(d.newTimeRemaining ?? 0);
      return `${formatSeconds(adj)} for ${d.teamName ?? "team"} (now ${formatTimeRemaining(remaining)})`;
    }

    case "draft_pick_changed":
      return `Pick #${d.pickNumber}: ${d.oldParticipantName} → ${d.newParticipantName}`;

    case "force_autopick":
      return `Auto-picked ${d.participantName} for ${d.teamName} at pick #${d.pickNumber}`;

    case "force_manual_pick":
      return `Picked ${d.participantName} for ${d.teamName} at pick #${d.pickNumber}`;

    case "draft_order_set":
      return "Draft order manually set";

    case "draft_order_randomized":
      return "Draft order randomized";

    case "draft_reset": {
      const prev = d.previousPickNumber;
      return prev !== null && prev !== undefined
        ? `Draft reset (was at pick #${prev})`
        : "Draft reset";
    }

    case "draft_started":
      return "Draft started";

    case "draft_paused":
      return d.pickNumber !== null && d.pickNumber !== undefined
        ? `Draft paused at pick #${d.pickNumber}`
        : "Draft paused";

    case "draft_resumed":
      return d.pickNumber !== null && d.pickNumber !== undefined
        ? `Draft resumed at pick #${d.pickNumber}`
        : "Draft resumed";

    case "league_settings_changed": {
      const fields = (d.changedFields as string[] | undefined) ?? [];
      const prev = (d.previousValues as Record<string, unknown> | undefined) ?? {};
      const next = (d.newValues as Record<string, unknown> | undefined) ?? {};
      const detail = diffLines(fields, prev, next, LEAGUE_FIELD_LABELS, formatLeagueField);
      return detail || "League settings updated";
    }

    case "draft_settings_changed": {
      const fields = (d.changedFields as string[] | undefined) ?? [];
      const prev = (d.previousValues as Record<string, unknown> | undefined) ?? {};
      const next = (d.newValues as Record<string, unknown> | undefined) ?? {};
      const detail = diffLines(fields, prev, next, DRAFT_FIELD_LABELS, formatDraftField);
      return detail || "Draft settings updated";
    }

    case "scoring_rules_changed": {
      const fields = (d.changedFields as string[] | undefined) ?? [];
      const prev = (d.previousValues as Record<string, unknown> | undefined) ?? {};
      const next = (d.newValues as Record<string, unknown> | undefined) ?? {};
      const detail = diffLines(fields, prev, next, SCORING_FIELD_LABELS, (_, v) => String(v ?? ""));
      return detail ? `Scoring updated: ${detail}` : "Scoring rules updated";
    }

    case "sports_changed": {
      const added = (d.added as string[] | undefined) ?? [];
      const removed = (d.removed as string[] | undefined) ?? [];
      const parts: string[] = [];
      if (added.length > 0) parts.push(`Added: ${truncateList(added)}`);
      if (removed.length > 0) parts.push(`Removed: ${truncateList(removed)}`);
      return parts.length > 0 ? parts.join(" | ") : "Sports updated";
    }

    case "brackt_resolved":
      return d.trigger === "auto" ? "Brackt resolved automatically" : "Brackt resolution retried";

    default:
      return (entry.action as string).replace(/_/g, " ");
  }
}
