/**
 * opportunityCache
 *
 * Redis-backed cache helpers for opportunity sub-resources:
 * activities, notes, contacts, products, company CW data, site data.
 */

import { redis } from "../../constants";
import { activityCw } from "../cw-utils/activities/activities";
import { opportunityCw } from "../cw-utils/opportunities/opportunities";

// ═══════════════════════════════════════════════════════════════════════════
// Key helpers
// ═══════════════════════════════════════════════════════════════════════════

export const activityCacheKey = (cwOppId: number) =>
  `opp:activities:${cwOppId}`;

export const companyCwCacheKey = (cwCompanyId: number) =>
  `opp:company-cw:${cwCompanyId}`;

export const notesCacheKey = (cwOppId: number) => `opp:notes:${cwOppId}`;

export const contactsCacheKey = (cwOppId: number) =>
  `opp:contacts:${cwOppId}`;

export const productsCacheKey = (cwOppId: number) =>
  `opp:products:${cwOppId}`;

export const siteCacheKey = (cwCompanyId: number, siteId: number) =>
  `opp:site:${cwCompanyId}:${siteId}`;

export const oppCwDataCacheKey = (cwOppId: number) =>
  `opp:cw-data:${cwOppId}`;

// ═══════════════════════════════════════════════════════════════════════════
// Generic helpers
// ═══════════════════════════════════════════════════════════════════════════

async function getJson<T>(key: string): Promise<T | null> {
  const raw = await redis.get(key);
  if (!raw) return null;
  try {
    return JSON.parse(raw) as T;
  } catch {
    return null;
  }
}

function isAxios404(err: unknown): boolean {
  const e = err as any;
  return e?.isAxiosError === true && e?.response?.status === 404;
}

function isTransient(err: unknown): boolean {
  const e = err as any;
  return (
    e?.isAxiosError === true &&
    (e?.code === "ECONNABORTED" ||
      e?.code === "ECONNRESET" ||
      e?.code === "ETIMEDOUT")
  );
}

// ═══════════════════════════════════════════════════════════════════════════
// Read helpers
// ═══════════════════════════════════════════════════════════════════════════

export async function getCachedActivities(
  cwOppId: number
): Promise<any[] | null> {
  return getJson<any[]>(activityCacheKey(cwOppId));
}

export async function getCachedCompanyCwData(
  cwCompanyId: number
): Promise<any | null> {
  return getJson<any>(companyCwCacheKey(cwCompanyId));
}

export async function getCachedNotes(cwOppId: number): Promise<any[] | null> {
  return getJson<any[]>(notesCacheKey(cwOppId));
}

export async function getCachedContacts(
  cwOppId: number
): Promise<any[] | null> {
  return getJson<any[]>(contactsCacheKey(cwOppId));
}

export async function getCachedProducts(cwOppId: number): Promise<any | null> {
  return getJson<any>(productsCacheKey(cwOppId));
}

export async function getCachedSite(
  cwCompanyId: number,
  siteId: number
): Promise<any | null> {
  return getJson<any>(siteCacheKey(cwCompanyId, siteId));
}

export async function getCachedOppCwData(cwOppId: number): Promise<any | null> {
  return getJson<any>(oppCwDataCacheKey(cwOppId));
}

// ═══════════════════════════════════════════════════════════════════════════
// Write helpers
// ═══════════════════════════════════════════════════════════════════════════

export async function fetchAndCacheActivities(
  cwOppId: number,
  ttlMs: number
): Promise<any[]> {
  try {
    const activities = await activityCw.fetchByOpportunityDirect(cwOppId);
    await redis.set(
      activityCacheKey(cwOppId),
      JSON.stringify(activities),
      "PX",
      ttlMs
    );
    return activities;
  } catch (err) {
    if (isAxios404(err) || isTransient(err)) return [];
    throw err;
  }
}

export async function fetchAndCacheNotes(
  cwOppId: number,
  ttlMs: number
): Promise<any[]> {
  try {
    const notes = await opportunityCw.fetchNotes(cwOppId);
    await redis.set(
      notesCacheKey(cwOppId),
      JSON.stringify(notes),
      "PX",
      ttlMs
    );
    return notes;
  } catch (err) {
    if (isAxios404(err) || isTransient(err)) return [];
    throw err;
  }
}
