/**
 * Audit Progress System
 * ─────────────────────
 * Tier definitions and helpers for updating progress during an audit run.
 * All labels are user-facing and white-labeled (no third-party names).
 */

import { prisma } from "@/lib/prisma";

// ─── Tier definitions ─────────────────────────────────────────────────────────

export interface TierDefinition {
  tier: number;
  label: string;           // Shown in the progress UI
  description: string;     // Longer tooltip / accessibility text
  estimatedSeconds: number;
}

export const AUDIT_TIERS: TierDefinition[] = [
  {
    tier: 1,
    label: "Initializing audit",
    description: "Setting up the audit context and preparing data connections.",
    estimatedSeconds: 5,
  },
  {
    tier: 2,
    label: "Discovering site structure",
    description: "Mapping the website's pages, navigation, and hierarchy.",
    estimatedSeconds: 45,
  },
  {
    tier: 3,
    label: "Analyzing technical SEO",
    description: "Inspecting site health, indexing signals, and crawlability.",
    estimatedSeconds: 75,
  },
  {
    tier: 4,
    label: "Evaluating content & metadata",
    description: "Reviewing page titles, descriptions, headers, and content depth.",
    estimatedSeconds: 45,
  },
  {
    tier: 5,
    label: "Identifying optimization gaps",
    description: "Surfacing missing best practices and structural weaknesses.",
    estimatedSeconds: 30,
  },
  {
    tier: 6,
    label: "Generating insights",
    description: "Synthesizing findings into a strategic narrative.",
    estimatedSeconds: 75,
  },
  {
    tier: 7,
    label: "Finalizing recommendations",
    description: "Prioritizing actions by impact and effort.",
    estimatedSeconds: 15,
  },
];

export const TOTAL_TIERS = AUDIT_TIERS.length;

// ─── Helpers ─────────────────────────────────────────────────────────────────

/** Estimated seconds remaining starting from (and including) the given tier. */
function estimateRemainingSeconds(fromTier: number): number {
  return AUDIT_TIERS.filter((t) => t.tier >= fromTier).reduce(
    (sum, t) => sum + t.estimatedSeconds,
    0,
  );
}

/** Advance to the given tier and persist progress fields. */
export async function advanceTier(auditId: string, tier: number): Promise<void> {
  const def = AUDIT_TIERS.find((t) => t.tier === tier);
  if (!def) throw new Error(`[audit-progress] Unknown tier ${tier}`);

  // Build the completed-tiers snapshot from all previous tiers
  const existing = await prisma.audit.findUnique({
    where: { id: auditId },
    select: { tiersCompleted: true },
  });

  const prev = (existing?.tiersCompleted as Array<{ tier: number; label: string; completedAt: string }>) ?? [];

  // Mark the PREVIOUS tier as completed (if advancing past it)
  const updatedCompleted =
    tier > 1
      ? [
          ...prev.filter((c) => c.tier !== tier - 1),
          {
            tier: tier - 1,
            label: AUDIT_TIERS.find((t) => t.tier === tier - 1)?.label ?? "",
            completedAt: new Date().toISOString(),
          },
        ]
      : prev;

  await prisma.audit.update({
    where: { id: auditId },
    data: {
      currentTier: tier,
      totalTiers: TOTAL_TIERS,
      currentTierLabel: def.label,
      tiersCompleted: updatedCompleted,
      estimatedSecondsRemaining: estimateRemainingSeconds(tier),
    },
  });
}

/** Mark an audit as started (status → running, record startedAt). */
export async function markStarted(auditId: string): Promise<void> {
  await prisma.audit.update({
    where: { id: auditId },
    data: { status: "running", startedAt: new Date() },
  });
}

/** Mark an audit as completed, recording all tiers as done. */
export async function markCompleted(auditId: string): Promise<void> {
  const allCompleted = AUDIT_TIERS.map((t) => ({
    tier: t.tier,
    label: t.label,
    completedAt: new Date().toISOString(),
  }));

  await prisma.audit.update({
    where: { id: auditId },
    data: {
      status: "completed",
      completedAt: new Date(),
      currentTier: TOTAL_TIERS,
      tiersCompleted: allCompleted,
      estimatedSecondsRemaining: 0,
    },
  });
}

/**
 * Write a granular progress step to the Audit record.
 * Call this at each major stage transition; detail is optional sub-status
 * (e.g. the URL currently being crawled).
 */
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export async function updateAuditProgress(
  auditId: string,
  step: number,
  label: string,
  detail?: string,
): Promise<void> {
  console.log(`[audit-progress] auditId=${auditId} step=${step} label="${label}"${detail ? ` detail="${detail}"` : ""}`);
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  await (prisma.audit.update as any)({
    where: { id: auditId },
    data: { progressStep: step, progressLabel: label, progressDetail: detail ?? null },
  });
}

/** Mark an audit as failed, saving internal + user-facing error messages. */
export async function markFailed(
  auditId: string,
  err: unknown,
  userFacingError?: string,
  errorReason?: string,
  errorDetail?: string,
): Promise<void> {
  const internalMsg =
    err instanceof Error ? `${err.name}: ${err.message}\n${err.stack ?? ""}` : String(err);

  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  await (prisma.audit.update as any)({
    where: { id: auditId },
    data: {
      status: "failed",
      completedAt: new Date(),
      errorLog: internalMsg,
      userFacingError:
        userFacingError ??
        "We encountered an issue completing this audit. Our team has been notified. Please try again in a few minutes.",
      ...(errorReason && { errorReason }),
      ...(errorDetail && { errorDetail }),
    },
  });
}