import { promises as fs } from "fs";
import path from "path";

const LOGS_DIR = path.join(process.cwd(), "logs");

export type AppErrorArea =
  | "oauth"
  | "datetime"
  | "generation"
  | "publish"
  | "schedule"
  | "context"
  | "db"
  | "sync"
  | "unknown";

export interface AppErrorLogEntry {
  timestamp: string;
  level: "ERROR" | "WARNING" | "INFO";
  area: AppErrorArea;
  event: string;
  projectId?: string;
  platform?: string;
  message: string;
  errorMessage?: string;
  stackTrace?: string;
  details?: Record<string, unknown>;
}

async function ensureLogsDir() {
  await fs.mkdir(LOGS_DIR, { recursive: true });
}

function logFilePath(date = new Date()) {
  return path.join(LOGS_DIR, `app-errors-${date.toISOString().slice(0, 10)}.log`);
}

function formatError(error: unknown): { errorMessage?: string; stackTrace?: string } {
  if (!error) return {};
  if (error instanceof Error) {
    return { errorMessage: error.message, stackTrace: error.stack };
  }
  return { errorMessage: String(error) };
}

/** Detect common MariaDB ISO datetime failures for clearer area tagging. */
export function classifyAppErrorArea(message: string, fallback: AppErrorArea = "unknown"): AppErrorArea {
  const m = message.toLowerCase();
  if (m.includes("incorrect datetime value") || m.includes("token_expires_at") || m.includes("last_synced_at")) {
    return "datetime";
  }
  if (m.includes("oauth") || m.includes("token") || m.includes("revoked")) return "oauth";
  if (m.includes("generat")) return "generation";
  if (m.includes("publish")) return "publish";
  if (m.includes("schedule")) return "schedule";
  if (m.includes("context")) return "context";
  if (m.includes("mysql") || m.includes("mariadb") || m.includes("er_")) return "db";
  return fallback;
}

/**
 * Append app/setup/runtime bugs for ops review.
 * File: `logs/app-errors-YYYY-MM-DD.log`
 */
export async function logAppError(input: {
  level?: "ERROR" | "WARNING" | "INFO";
  area?: AppErrorArea;
  event: string;
  projectId?: string;
  platform?: string;
  message: string;
  error?: unknown;
  details?: Record<string, unknown>;
}): Promise<AppErrorLogEntry> {
  await ensureLogsDir();
  const { errorMessage, stackTrace } = formatError(input.error);
  const area =
    input.area ??
    classifyAppErrorArea(errorMessage || input.message, "unknown");

  const entry: AppErrorLogEntry = {
    timestamp: new Date().toISOString(),
    level: input.level ?? "ERROR",
    area,
    event: input.event,
    projectId: input.projectId,
    platform: input.platform,
    message: input.message,
    errorMessage,
    stackTrace,
    details: input.details,
  };

  try {
    await fs.appendFile(logFilePath(), `${JSON.stringify(entry)}\n`, "utf-8");
  } catch (err) {
    console.error("[PostSync] Failed to write app-errors log:", err);
  }

  return entry;
}
