import { getActiveScheduleSlots } from "./slot-check";
import { buildPlannedScheduleView, resolveScheduleSeed } from "./resolve-schedule";
import { wasSlotFiredToday } from "./slot-fire-state";
import { hasUsablePostingContext, hasUsableSchedule } from "./setup-ready";
import { ensureFreshAccountTokens } from "@/lib/social/ensure-publish-tokens";
import { summarizePublishAccounts } from "@/lib/social/publish-readiness";
import { listQueuedPostsForPublish } from "@/lib/storage/generated-posts";
import { getUserProjects } from "@/lib/storage/projects";
import type { Project } from "@/types/workflow";
import type { ProjectScopedData } from "@/lib/project/defaults";

export interface ScheduleReadinessCheck {
  ok: boolean;
  label: string;
  detail: string;
}

export interface ProjectScheduleReadiness {
  projectId: string;
  projectName: string;
  ready: boolean;
  checks: ScheduleReadinessCheck[];
  plannedSlots: string[];
  activeSlots: string[];
  cronConfigured: boolean;
  serverSynced: boolean;
  queuedPosts: Array<{ id: string; title: string; status: string }>;
  queuedCount: number;
  timezoneLabel: string;
  scheduleSeed: number;
}

function automationEnabled(
  automation: Record<string, boolean> | undefined,
  ruleId: string,
  defaultOn: boolean,
): boolean {
  return automation?.[ruleId] ?? defaultOn;
}

export async function evaluateProjectScheduleReadiness(input: {
  userId: string;
  project: Project;
  data: ProjectScopedData | undefined;
  now?: Date;
}): Promise<ProjectScheduleReadiness> {
  const { userId, project, data, now = new Date() } = input;
  const checks: ScheduleReadinessCheck[] = [];
  const cronConfigured = Boolean(process.env.CRON_SECRET?.trim());

  checks.push({
    ok: cronConfigured,
    label: "Server cron",
    detail: cronConfigured
      ? "CRON_SECRET is set — internal poller runs every 5 min (or use Linux cron on /api/cron/scheduled-publish)."
      : "CRON_SECRET missing on server — automated posts will never run.",
  });

  checks.push({
    ok: project.status === "active",
    label: "Project active",
    detail:
      project.status === "active"
        ? "Project is Active."
        : "Project is Paused — auto-publish is disabled.",
  });

  const scheduleSaved = hasUsableSchedule(data?.schedule);
  checks.push({
    ok: scheduleSaved,
    label: "Schedule saved",
    detail: scheduleSaved
      ? `Smart Schedule ready (${data?.schedule?.postsPerDay ?? 2} posts/day).`
      : "Open Smart Schedule → choose posts/day → click Save Schedule.",
  });

  const smartTiming = automationEnabled(data?.automation, "smart-timing", true);
  checks.push({
    ok: smartTiming,
    label: "Smart timing",
    detail: smartTiming
      ? "Automation → Smart Random Timing is ON."
      : "Turn ON Smart Random Timing in Automation Rules.",
  });

  const loopSequence = automationEnabled(data?.automation, "loop-sequence", true);
  checks.push({
    ok: loopSequence,
    label: "Loop sequence",
    detail: loopSequence
      ? "Automation → Loop Post Sequence is ON (auto-generate + direct publish at slot)."
      : "Turn ON Loop Post Sequence: left menu → Automation → toggle Loop Post Sequence.",
  });

  const contextSaved = hasUsablePostingContext(data?.context);
  checks.push({
    ok: contextSaved,
    label: "Posting context",
    detail: contextSaved
      ? "Posting context / post sequence is ready."
      : "Open Posting Context → click Save Context.",
  });

  const serverAccounts = await ensureFreshAccountTokens(userId, project.id);
  const publishSummary = summarizePublishAccounts({
    clientAccounts: data?.accounts ?? [],
    serverAccounts,
  });
  const publishReady = publishSummary.ready;
  checks.push({
    ok: publishReady.length > 0,
    label: "Connected accounts",
    detail: publishSummary.detail,
  });

  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 plannedSlots = scheduleView.slotTimes;
  const activeSlots = getActiveScheduleSlots({
    timezone: project.timezone,
    postsPerDay,
    scheduleSeed,
    now,
  }).map((s) => s.display);

  const inWindow = activeSlots.length > 0;
  const queued = await listQueuedPostsForPublish(project.id, project.name);
  const queuedSummary = queued.map((p) => ({ id: p.id, title: p.title, status: p.status }));

  // Informational only — outside slot with no draft is normal waiting, not a setup failure.
  checks.push({
    ok: true,
    label: "Content queued for schedule",
    detail:
      queued.length > 0
        ? `${queued.length} post(s) ready — "${queued[0].title}" publishes at the next slot (no approval).`
        : loopSequence
          ? `No draft queued yet — OK. With Loop Post Sequence ON, cron will auto-generate and publish at: ${plannedSlots.join(" · ")}. Or use Live Generation → Generate Now to queue early.`
          : `No draft queued. Turn ON Loop Post Sequence in Automation (left menu → Automation), or Generate Now in Live Generation.`,
  });

  checks.push({
    ok: true,
    label: "Current time slot",
    detail: inWindow
      ? `Inside slot now: ${activeSlots.join(", ")} (${scheduleView.timezoneLabel}) — cron should generate/publish within this window.`
      : queued.length > 0
        ? `Outside slot now — waiting for ${scheduleView.slots.map((s) => s.display).join(" · ")} ${scheduleView.timezoneLabel}. Cron fires within ±30 min of each time.`
        : `Outside slot now (waiting). Next windows: ${scheduleView.slots.map((s) => s.display).join(" · ")} ${scheduleView.timezoneLabel}.`,
  });

  const activeSlotLabels = getActiveScheduleSlots({
    timezone: project.timezone,
    postsPerDay,
    scheduleSeed,
    now,
  });
  for (const slot of activeSlotLabels) {
    const fired = await wasSlotFiredToday(project.id, slot.label, project.timezone, now);
    if (fired) {
      const nextSlot =
        postsPerDay === 2 && slot.label === "Morning"
          ? scheduleView.slots.find((s) => s.label === "Evening")?.display ?? "evening slot"
          : "tomorrow's morning slot";
      checks.push({
        ok: true,
        label: `${slot.label} slot today`,
        detail: `${slot.label} already fired today — next publish at ${nextSlot}.`,
      });
    }
  }

  // Only real blockers count toward "ready" (exclude informational queue/slot rows).
  const blockingChecks = checks.filter(
    (c) => c.label !== "Content queued for schedule" && c.label !== "Current time slot",
  );
  const ready = blockingChecks.every((c) => c.ok);

  return {
    projectId: project.id,
    projectName: project.name,
    ready,
    checks,
    plannedSlots,
    activeSlots,
    cronConfigured,
    serverSynced: Boolean(data),
    queuedPosts: queuedSummary,
    queuedCount: queued.length,
    timezoneLabel: scheduleView.timezoneLabel,
    scheduleSeed,
  };
}

export async function evaluateUserScheduleReadiness(
  userId: string,
  projectId?: string,
  now = new Date(),
): Promise<ProjectScheduleReadiness[]> {
  const snapshot = await getUserProjects(userId);
  if (!snapshot) return [];

  const projects = projectId
    ? snapshot.projects.filter((p) => p.id === projectId)
    : snapshot.projects;

  const results: ProjectScheduleReadiness[] = [];
  for (const project of projects) {
    results.push(
      await evaluateProjectScheduleReadiness({
        userId,
        project,
        data: snapshot.dataByProjectId[project.id],
        now,
      }),
    );
  }
  return results;
}
