// markerUtils.js - Utility functions for markers

import { loadAuth, guessUsernameFromToken } from "../../auth/authStorage";
import { fetchProfile } from "../../api/client";

export const SW_ANIM_MS = 840;
export const HEATMAP_ENABLED = false;

const avatarCache = new Map();
const avatarInflight = new Map();

export function applyAvatar(el, username, url) {
  if (!el) return;
  const initial = (username || "U")[0]?.toUpperCase() || "U";
  el.innerHTML = "";
  if (url) {
    const img = document.createElement("img");
    img.src = url;
    img.alt = username || "user";
    el.appendChild(img);
  } else {
    el.textContent = initial;
  }
}

export function hydrateAvatars(root) {
  if (!root) return;
  const avatarEls = root.querySelectorAll("[data-username]");
  avatarEls.forEach((el) => {
    const username = el.getAttribute("data-username")?.trim();
    if (!username) return;
    if (avatarCache.has(username)) {
      applyAvatar(el, username, avatarCache.get(username));
      return;
    }
    if (avatarInflight.has(username)) return;
    avatarInflight.set(username, true);
    fetchProfile(username)
      .then((profile) => {
        const url = profile?.profile_picture || profile?.picture || "";
        avatarCache.set(username, url);
        applyAvatar(el, username, url);
      })
      .catch(() => {
        avatarCache.set(username, "");
        applyAvatar(el, username, "");
      })
      .finally(() => avatarInflight.delete(username));
  });
}

export function escapeHtml(str) {
  return String(str ?? "")
    .replace(/&/g, "&amp;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;");
}

export function formatCount(value) {
  const n = parseInt(value, 10);
  if (Number.isNaN(n) || n <= 0) return "0";
  if (n >= 1000000) return (n / 1000000).toFixed(1).replace(/\.0$/, "") + "M";
  if (n >= 1000) return (n / 1000).toFixed(1).replace(/\.0$/, "") + "K";
  return String(n);
}

export function readCount(post, keys) {
  for (const k of keys) {
    const v = post?.[k];
    if (v !== undefined && v !== null) {
      const n = parseInt(v, 10);
      if (!Number.isNaN(n) && n >= 0) return n;
    }
  }
  return 0;
}

export function updateStat(modalWrap, statKey, value) {
  const el = modalWrap?.querySelector(`[data-stat="${statKey}"]`);
  if (el) el.textContent = formatCount(value);
}

export function clamp(v, min, max) {
  return Math.max(min, Math.min(max, v));
}

export function isAuthed() {
  try {
    const auth = loadAuth();
    return !!(auth?.access_token);
  } catch {
    return false;
  }
}

export function getAuthInfo() {
  let authToken = "";
  let currentUsername = "";
  try {
    const auth = loadAuth();
    authToken = auth?.access_token || "";
    currentUsername = guessUsernameFromToken(authToken) || "";
  } catch {}
  return { authToken, currentUsername };
}

export function requestAuth(message, mode = "login") {
  try {
    window.dispatchEvent(
      new CustomEvent("sociowire:request-auth", {
        detail: { message, mode },
      })
    );
  } catch {}
}

export function formatRelativeTime(createdAt) {
  const created = typeof createdAt === "string" ? new Date(createdAt) : createdAt;
  const now = new Date();
  const diffSec = Math.floor((now.getTime() - created.getTime()) / 1000);
  if (diffSec < 60) return "now";
  if (diffSec < 3600) return `${Math.floor(diffSec / 60)}m`;
  if (diffSec < 86400) return `${Math.floor(diffSec / 3600)}h`;
  if (diffSec < 604800) return `${Math.floor(diffSec / 86400)}d`;
  return created.toLocaleDateString();
}

export function getPostTime(post) {
  const raw =
    post?.published_at ||
    post?.publishedAt ||
    post?.PublishedAt ||
    post?.created_at ||
    post?.createdAt ||
    post?.CreatedAt ||
    "";
  if (!raw) return { date: new Date(), relTime: "now" };
  const d = new Date(raw);
  if (Number.isNaN(d.getTime())) return { date: new Date(), relTime: "now" };
  return { date: d, relTime: formatRelativeTime(d) };
}

export function truthScore(post) {
  const rawTruth = post?.truth_score ?? post?.truthScore ?? post?.TruthScore ?? 0;
  const rawAI = post?.truth_ai ?? post?.truthAI ?? post?.TruthAI ?? 0;
  let score = 0;
  if (typeof rawTruth === "number" && rawTruth > 0) {
    score = rawTruth;
  } else if (typeof rawAI === "number" && rawAI > 0) {
    score = rawAI;
  }
  return clamp(Math.round(score), 0, 100);
}

export function truthColor(score) {
  if (score >= 70) return "#22c55e";
  if (score >= 40) return "#eab308";
  return "#ef4444";
}

export function normCatLabel(post) {
  const cat = (post?.category || "").toString().trim();
  const sub = (post?.sub_category || post?.subCategory || "").toString().trim();
  const c = cat.charAt(0).toUpperCase() + cat.slice(1).toLowerCase();
  if (sub) return `${c} • ${sub}`;
  return c;
}

export function categoryIconClass(post) {
  const cat = (post?.category || "").toString().toLowerCase();
  switch (cat) {
    case "news":
      return "fa-newspaper";
    case "event":
      return "fa-calendar";
    case "market":
      return "fa-store";
    case "friends":
      return "fa-users";
    default:
      return "fa-globe";
  }
}

export function isClusterMainPost(post) {
  if (!post) return false;
  const clusterPostId = post.cluster_post_id ?? post.clusterPostId;
  const postId = post.id ?? post.ID ?? post.post_id;
  if (clusterPostId && postId && clusterPostId === postId) {
    const members = post.cluster_members ?? post.clusterMembers ?? [];
    return Array.isArray(members) && members.length > 1;
  }
  return false;
}

export function hashPostId(id) {
  let n = typeof id === "number" ? id : parseInt(id, 10);
  if (Number.isNaN(n)) n = 0;
  n = ((n >>> 16) ^ n) * 0x45d9f3b;
  n = ((n >>> 16) ^ n) * 0x45d9f3b;
  n = (n >>> 16) ^ n;
  return n >>> 0;
}
