import { getActiveScheduleSlots } from "./slot-check";
import { buildPlannedScheduleView, resolveScheduleSeed } from "./resolve-schedule";
import { wasSlotFiredToday } from "./slot-fire-state";
import { getAutoPostLockState, isAutoPostRunInProgress } from "./auto-post-lock";
import { hasUsablePostingContext, hasUsableSchedule } from "./setup-ready";
import { isAccountPublishReady } from "@/lib/social/token-validation";
import { ensureFreshAccountTokens } from "@/lib/social/ensure-publish-tokens";
import { getAccountPublishBlockReason, summarizePublishAccounts } from "@/lib/social/publish-readiness";
import { isPlatformPublishReady } from "@/lib/social/platforms";
import { mergeAccountsForPublish } from "@/lib/storage/social-accounts";
import { listQueuedPostsForPublish } from "@/lib/storage/generated-posts";
import { getUserProjects, listAllUserIds } from "@/lib/storage/projects";
import { loadProviderPostStats } from "@/lib/storage/provider-post-stats";
import type { Project } from "@/types/workflow";
import type { ProjectScopedData } from "@/lib/project/defaults";

export interface AutoPostTraceStep {
  step: string;
  ok: boolean;
  detail: string;
  blocker: boolean;
}

export interface ProjectAutoPostDiagnostics {
  projectId: string;
  projectName: string;
  projectStatus: string;
  canAutoPost: boolean;
  executionStopsAt: string | null;
  trace: AutoPostTraceStep[];
  plannedSlots: string[];
  activeSlotsNow: string[];
  queuedCount: number;
  queuedPosts: Array<{ id: string; title: string; status: string }>;
  providers: Array<{
    platform: string;
    ready: boolean;
    connectionStatus: string;
    lastSuccessAt?: string;
    successCount: number;
    lastError?: string;
  }>;
  automation: Record<string, boolean>;
}

export interface AutoPostSystemDiagnostics {
  checkedAt: string;
  cronSecretConfigured: boolean;
  internalPollerEnabled: boolean;
  pollerRunning: boolean;
  lockState: ReturnType<typeof getAutoPostLockState>;
  userDataFound: boolean;
  userIds: string[];
  projects: ProjectAutoPostDiagnostics[];
  summary: string;
}

function humanizeBlockerStep(step: string | null): string {
  if (!step) return "unknown";
  const map: Record<string, string> = {
    scheduler_config: "CRON_SECRET not configured",
    project_active: "project is paused",
    schedule_saved: "Smart Schedule not saved",
    smart_timing_enabled: "Smart Random Timing is off",
    providers_validated: "no publish-ready connected accounts",
    proposal_queued: "no post ready — enable Loop Post Sequence (auto-generate + publish) or generate once",
    eligibility_score: "engagement score below threshold",
    inside_schedule_slot: "outside schedule window",
  };
  return map[step] ?? step.replace(/_/g, " ");
}

function automationEnabled(
  automation: Record<string, boolean> | undefined,
  ruleId: string,
  defaultOn: boolean,
): boolean {
  return automation?.[ruleId] ?? defaultOn;
}

async function traceProject(input: {
  userId: string;
  project: Project;
  data: ProjectScopedData | undefined;
  now: Date;
}): Promise<ProjectAutoPostDiagnostics> {
  const { project, data, now } = input;
  const trace: AutoPostTraceStep[] = [];

  const push = (step: string, ok: boolean, detail: string, blocker = false) => {
    trace.push({ step, ok, detail, blocker });
  };

  push(
    "scheduler_config",
    Boolean(process.env.CRON_SECRET?.trim()),
    process.env.CRON_SECRET?.trim()
      ? "CRON_SECRET is set — scheduler can run."
      : "CRON_SECRET missing — auto-post scheduler disabled.",
    !process.env.CRON_SECRET?.trim(),
  );

  push(
    "project_active",
    project.status === "active",
    project.status === "active"
      ? "Project is Active."
      : `Project is ${project.status} — auto-post paused.`,
    project.status !== "active",
  );

  const scheduleSaved = hasUsableSchedule(data?.schedule);
  push(
    "schedule_saved",
    scheduleSaved,
    scheduleSaved
      ? `Schedule ready (${data?.schedule?.postsPerDay ?? 2} posts/day).`
      : "Smart Schedule not saved — open Smart Schedule and click Save.",
    !scheduleSaved,
  );

  const smartTiming = automationEnabled(data?.automation, "smart-timing", true);
  push(
    "smart_timing_enabled",
    smartTiming,
    smartTiming
      ? "Automation → Smart Random Timing is ON."
      : "Smart Random Timing is OFF — enable in Automation Rules.",
    !smartTiming,
  );

  const contextSaved = hasUsablePostingContext(data?.context);
  push(
    "context_saved",
    contextSaved,
    contextSaved
      ? "Posting context / post sequence is ready."
      : "Posting context not saved — Save Context required.",
    false,
  );

  const postsPerDay = (data?.schedule?.postsPerDay ?? 2) as 1 | 2;
  const scheduleSeed = resolveScheduleSeed(project.id, data?.schedule?.scheduleSeed);
  const scheduleView = buildPlannedScheduleView({
    projectId: project.id,
    timezone: project.timezone,
    postsPerDay,
    scheduleSeed,
  });

  const activeSlots = getActiveScheduleSlots({
    timezone: project.timezone,
    postsPerDay,
    scheduleSeed,
    now,
  });

  push(
    "inside_schedule_slot",
    activeSlots.length > 0,
    activeSlots.length > 0
      ? `Inside slot window: ${activeSlots.map((s) => s.display).join(", ")}.`
      : `Outside slot — next: ${scheduleView.slotTimes.join(" · ")}. Cron fires within ±30 min of each.`,
    false,
  );

  if (activeSlots.length > 0) {
    for (const slot of activeSlots) {
      const fired = await wasSlotFiredToday(project.id, slot.label, project.timezone, now);
      push(
        `slot_${slot.label.toLowerCase()}_status`,
        true,
        fired
          ? `${slot.label} already fired today — waiting for the next schedule slot (not a setup error).`
          : `${slot.label} slot ready to fire now.`,
        false,
      );
    }
  }

  const serverAccounts = await ensureFreshAccountTokens(input.userId, project.id);
  const clientAccounts = data?.accounts ?? [];
  const publishSummary = summarizePublishAccounts({
    clientAccounts,
    serverAccounts,
  });
  push(
    "providers_validated",
    publishSummary.ready.length > 0,
    publishSummary.detail,
    publishSummary.ready.length === 0,
  );

  const queued = await listQueuedPostsForPublish(project.id, project.name);
  const loopSequence = automationEnabled(data?.automation, "loop-sequence", true);
  push(
    "proposal_queued",
    queued.length > 0 || loopSequence,
    queued.length > 0
      ? `${queued.length} post(s) queued — next: "${queued[0].title}" (drafts publish at slot — no approval).`
      : loopSequence
        ? "No queued post — Loop Post Sequence will auto-generate and publish directly at slot time."
        : "No post queued — enable Loop Post Sequence or generate content in Live Generation.",
    !loopSequence && queued.length === 0,
  );

  const highScore = automationEnabled(data?.automation, "high-score", false);
  if (queued.length > 0 && highScore) {
    const next = queued[0];
    const approved = next.status === "approved";
    const scoreOk = approved || (next.engagementScore ?? 0) >= 80;
    push(
      "eligibility_score",
      scoreOk,
      approved
        ? "User-approved post — score check bypassed."
        : scoreOk
          ? `Engagement score ${next.engagementScore} meets threshold (80).`
          : `Score ${next.engagementScore ?? 0} below 80 — enable high-score rule or lower threshold.`,
      !scoreOk,
    );
  }

  const stats = await loadProviderPostStats(project.id);
  const mergedForDisplay = mergeAccountsForPublish(clientAccounts, serverAccounts);
  const providers = mergedForDisplay
    .filter((a) => isPlatformPublishReady(a.platform))
    .map((a) => {
      const stat = stats.find((s) => s.platform === a.platform);
      const blockReason = getAccountPublishBlockReason(a);
      return {
        platform: a.platform,
        ready: isAccountPublishReady(a),
        connectionStatus: a.connectionStatus ?? (a.connected ? "connected" : "disconnected"),
        lastSuccessAt: stat?.lastSuccessAt,
        successCount: stat?.successCount ?? 0,
        lastError: stat?.lastError ?? blockReason ?? undefined,
      };
    });

  const blocker = trace.find((t) => t.blocker && !t.ok);
  const canAutoPost = !blocker;

  return {
    projectId: project.id,
    projectName: project.name,
    projectStatus: project.status,
    canAutoPost,
    executionStopsAt: blocker?.step ?? null,
    trace,
    plannedSlots: scheduleView.slotTimes,
    activeSlotsNow: activeSlots.map((s) => s.display),
    queuedCount: queued.length,
    queuedPosts: queued.map((p) => ({ id: p.id, title: p.title, status: p.status })),
    providers,
    automation: data?.automation ?? {},
  };
}

export async function evaluateAutoPostDiagnostics(
  userId?: string,
  projectId?: string,
  now = new Date(),
): Promise<AutoPostSystemDiagnostics> {
  const cronSecretConfigured = Boolean(process.env.CRON_SECRET?.trim());
  const internalPollerEnabled =
    cronSecretConfigured && process.env.DISABLE_INTERNAL_CRON !== "true";

  const userIds = userId ? [userId] : await listAllUserIds();
  const projects: ProjectAutoPostDiagnostics[] = [];

  for (const uid of userIds) {
    const snapshot = await getUserProjects(uid);
    if (!snapshot) continue;

    const projectList = projectId
      ? snapshot.projects.filter((p) => p.id === projectId)
      : snapshot.projects;

    for (const project of projectList) {
      projects.push(
        await traceProject({
          userId: uid,
          project,
          data: snapshot.dataByProjectId[project.id],
          now,
        }),
      );
    }
  }

  const blocked = projects.filter((p) => !p.canAutoPost);
  const queuedReady = projects.filter((p) => p.canAutoPost && p.queuedCount > 0);
  const summary =
    !cronSecretConfigured
      ? "Auto-post blocked: CRON_SECRET not configured on server."
      : blocked.length === projects.length && projects.length > 0
        ? `Auto-post blocked. First blocker: ${humanizeBlockerStep(blocked[0].executionStopsAt)}.`
        : queuedReady.length > 0
          ? `${queuedReady.length} project(s) queued — cron publishes at the next morning/evening slot (±30 min).`
          : projects.some((p) => p.canAutoPost)
            ? "At least one project is ready to auto-post when the slot window opens."
            : "No projects found — save project setup while logged in.";

  return {
    checkedAt: now.toISOString(),
    cronSecretConfigured,
    internalPollerEnabled,
    pollerRunning: isAutoPostRunInProgress(),
    lockState: getAutoPostLockState(),
    userDataFound: userIds.length > 0,
    userIds,
    projects,
    summary,
  };
}
