// @File: src/lib/visitorTracking.ts
// @Desc: Lightweight visitor-tracking client. Generates/persists a session
//        id in sessionStorage, captures UTM parameters on landing, and posts
//        pageview/event payloads to /api/v1/track/*. All failures are silent
//        — tracking never blocks the user-facing app.
import { getToken } from "@/lib/auth";

const SESSION_KEY = "vm_session_id";
const UTM_KEY = "vm_utm_params";

const UTM_FIELDS = [
  "utm_source",
  "utm_medium",
  "utm_campaign",
  "utm_term",
  "utm_content",
] as const;

type UtmRecord = Partial<Record<(typeof UTM_FIELDS)[number], string>>;

function randomSessionId(): string {
  // Prefer crypto.randomUUID when available; fall back to a timestamp+random
  // composite to keep older browsers working.
  try {
    if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
      return crypto.randomUUID().replace(/-/g, "").slice(0, 32);
    }
  } catch {
    /* ignore */
  }
  const rand = Math.random().toString(36).slice(2, 10);
  return `${Date.now().toString(36)}${rand}`;
}

export function getSessionId(): string {
  if (typeof window === "undefined") return "ssr";
  try {
    const existing = window.sessionStorage.getItem(SESSION_KEY);
    if (existing) return existing;
    const fresh = randomSessionId();
    window.sessionStorage.setItem(SESSION_KEY, fresh);
    return fresh;
  } catch {
    return randomSessionId();
  }
}

function captureUtmFromUrl(): UtmRecord {
  if (typeof window === "undefined") return {};
  try {
    const params = new URLSearchParams(window.location.search);
    const picked: UtmRecord = {};
    for (const key of UTM_FIELDS) {
      const value = params.get(key);
      if (value) picked[key] = value.slice(0, 100);
    }
    return picked;
  } catch {
    return {};
  }
}

export function getStoredUtm(): UtmRecord {
  if (typeof window === "undefined") return {};
  try {
    const raw = window.sessionStorage.getItem(UTM_KEY);
    if (raw) {
      const parsed = JSON.parse(raw);
      if (parsed && typeof parsed === "object") return parsed as UtmRecord;
    }
  } catch {
    /* ignore */
  }
  const fresh = captureUtmFromUrl();
  if (Object.keys(fresh).length > 0) {
    try {
      window.sessionStorage.setItem(UTM_KEY, JSON.stringify(fresh));
    } catch {
      /* ignore */
    }
  }
  return fresh;
}

function authHeaders(): HeadersInit {
  const token = getToken();
  const h: Record<string, string> = { "Content-Type": "application/json" };
  if (token) h.Authorization = `Bearer ${token}`;
  return h;
}

async function postJson(path: string, body: Record<string, unknown>): Promise<void> {
  try {
    await fetch(path, {
      method: "POST",
      headers: authHeaders(),
      body: JSON.stringify(body),
      keepalive: true,
    });
  } catch {
    /* tracking failures are silent */
  }
}

export async function trackPageview(page: string): Promise<void> {
  if (typeof window === "undefined") return;
  const utm = getStoredUtm();
  await postJson("/api/v1/track/pageview", {
    session_id: getSessionId(),
    page,
    referrer: document.referrer || null,
    ...utm,
    screen: `${window.innerWidth}x${window.innerHeight}`,
  });
}

export async function trackEvent(
  eventType: string,
  opts?: { label?: string; page?: string; metadata?: Record<string, unknown> },
): Promise<void> {
  if (typeof window === "undefined") return;
  await postJson("/api/v1/track/event", {
    session_id: getSessionId(),
    event_type: eventType,
    label: opts?.label ?? null,
    page: opts?.page ?? window.location.pathname,
    metadata: opts?.metadata ?? null,
  });
}

export async function trackHeartbeat(): Promise<void> {
  if (typeof window === "undefined") return;
  await postJson("/api/v1/track/heartbeat", {
    session_id: getSessionId(),
    event_type: "heartbeat",
    page: window.location.pathname,
  });
}