/**
 * Social publishing audit trail (JSONL). Never log tokens/secrets.
 */

import { promises as fs } from "fs";
import path from "path";
import { randomUUID } from "crypto";

const LOGS_DIR = path.join(process.cwd(), "logs");

export type SocialAuditAction =
  | "POST_CREATED"
  | "PUBLISH_REQUESTED"
  | "JOB_QUEUED"
  | "PUBLISH_STARTED"
  | "PUBLISH_SUCCESS"
  | "PUBLISH_FAILED"
  | "PUBLISH_SKIPPED"
  | "RETRY_STARTED"
  | "TOKEN_REFRESHED"
  | "TOKEN_EXPIRED"
  | "ACCOUNT_RECONNECTED";

export interface SocialPublishAuditEntry {
  id: string;
  projectId?: string;
  userId?: string;
  postId?: string;
  publishJobId?: string;
  platform?: string;
  destinationId?: string;
  action: SocialAuditAction;
  status?: string;
  errorCode?: string;
  errorMessage?: string;
  /** Sanitized provider metadata only — never tokens. */
  providerResponse?: Record<string, unknown>;
  providerPostId?: string;
  providerUrl?: string;
  createdAt: string;
  publishedAt?: string;
}

const SENSITIVE_KEY = /token|secret|password|authorization|cookie|apikey|api_key/i;

function sanitizeDetails(
  details: Record<string, unknown> | undefined,
): Record<string, unknown> | undefined {
  if (!details) return undefined;
  const out: Record<string, unknown> = {};
  for (const [k, v] of Object.entries(details)) {
    if (SENSITIVE_KEY.test(k)) {
      out[k] = "[redacted]";
      continue;
    }
    if (typeof v === "string" && v.length > 500) {
      out[k] = `${v.slice(0, 500)}…`;
      continue;
    }
    out[k] = v;
  }
  return out;
}

function auditFilename() {
  return `social-audit-${new Date().toISOString().slice(0, 10)}.log`;
}

export async function writeSocialPublishAudit(
  entry: Omit<SocialPublishAuditEntry, "id" | "createdAt"> & {
    id?: string;
    createdAt?: string;
  },
): Promise<SocialPublishAuditEntry> {
  await fs.mkdir(LOGS_DIR, { recursive: true });
  const full: SocialPublishAuditEntry = {
    ...entry,
    id: entry.id ?? `aud_${randomUUID().replace(/-/g, "").slice(0, 12)}`,
    createdAt: entry.createdAt ?? new Date().toISOString(),
    providerResponse: sanitizeDetails(entry.providerResponse),
    errorMessage: entry.errorMessage?.slice(0, 1000),
  };
  await fs.appendFile(
    path.join(LOGS_DIR, auditFilename()),
    `${JSON.stringify(full)}\n`,
    "utf-8",
  );
  return full;
}

export async function readSocialPublishAudit(input?: {
  projectId?: string;
  postId?: string;
  platform?: string;
  limit?: number;
  date?: string;
}): Promise<SocialPublishAuditEntry[]> {
  const limit = input?.limit ?? 100;
  const date = input?.date ?? new Date().toISOString().slice(0, 10);
  const file = path.join(LOGS_DIR, `social-audit-${date}.log`);
  let raw = "";
  try {
    raw = await fs.readFile(file, "utf-8");
  } catch {
    return [];
  }
  const entries: SocialPublishAuditEntry[] = [];
  for (const line of raw.trim().split("\n").filter(Boolean)) {
    try {
      const e = JSON.parse(line) as SocialPublishAuditEntry;
      if (input?.projectId && e.projectId !== input.projectId) continue;
      if (input?.postId && e.postId !== input.postId) continue;
      if (input?.platform && e.platform !== input.platform) continue;
      entries.push(e);
    } catch {
      // skip bad lines
    }
  }
  return entries.slice(-limit).reverse();
}
