// =============================================================================
// HeadlineSift.com — Sources Admin Page
// =============================================================================
// Server component — queries Prisma, reads searchParams, renders the CRUD UI.

import type { Metadata } from "next";
import { prisma } from "@/lib/db/client";
import { SourcesPageClient } from "./SourcesPageClient";
import type { SourceRow } from "./SourceTable";

export const metadata: Metadata = { title: "Sources" };

// ============================================================================
// Types
// ============================================================================

interface SourcesPageProps {
  searchParams: Promise<{
    search?: string;
    edit?: string;
    success?: string;
    error?: string;
    type?: string;
    status?: string;
    language?: string;
    isOfficial?: string;
  }>;
}

// Clean up success/error messages from searchParams
function successMessage(key: string): string | null {
  // Dynamic messages: "fetched:new:dupes"
  if (key.startsWith("fetched:")) {
    const parts = key.split(":");
    const newCount = parseInt(parts[1] || "0", 10);
    const dupeCount = parseInt(parts[2] || "0", 10);
    if (newCount === 0) {
      return `Fetch complete — 0 new articles, ${dupeCount} duplicates found.`;
    }
    return `Fetch complete — ${newCount} new article${newCount !== 1 ? "s" : ""} saved${dupeCount > 0 ? `, ${dupeCount} duplicate${dupeCount !== 1 ? "s" : ""} skipped` : ""}.`;
  }

  const messages: Record<string, string> = {
    created: "Source created successfully.",
    updated: "Source updated successfully.",
    deleted: "Source deleted successfully.",
    activated: "Source activated — it will be eligible for fetching.",
    deactivated: "Source deactivated — it will be excluded from fetching.",
  };
  return messages[key] ?? null;
}

/**
 * Compute a health summary from fetch status and failure count.
 * Returns a simple enum that the table can render as a colored dot.
 */
function sourceHealth(
  lastFetchStatus: string | null,
  consecutiveFailures: number,
): "healthy" | "warning" | "error" | "unknown" {
  if (!lastFetchStatus) return "unknown";
  if (lastFetchStatus === "FAILED" || consecutiveFailures >= 3) return "error";
  if (lastFetchStatus === "PARTIAL" || consecutiveFailures >= 1) return "warning";
  if (lastFetchStatus === "SUCCESS" && consecutiveFailures === 0) return "healthy";
  return "unknown";
}

// ============================================================================
// Page
// ============================================================================

export default async function SourcesPage({ searchParams }: SourcesPageProps) {
  const params = await searchParams;
  const search = params.search?.trim() ?? "";
  const editId = params.edit ?? null;
  const successKey = params.success ?? null;
  const errorKey = params.error ?? null;
  const typeFilter = params.type ?? null;
  const statusFilter = params.status ?? null;
  const languageFilter = params.language ?? null;
  const isOfficialFilter = params.isOfficial ?? null;

  // ---- Resolve messages ----
  const successMsg = successKey ? successMessage(successKey) : null;
  const errorMsg = errorKey ? errorKey.replace(/\+/g, " ") : null;

  // ---- Build where clause ----
  const where: Record<string, unknown> = {};

  if (search) {
    where.OR = [
      { name: { contains: search } },
      { websiteUrl: { contains: search } },
    ];
  }

  if (typeFilter && ["RSS", "API", "MANUAL", "SCRAPE"].includes(typeFilter)) {
    where.sourceType = typeFilter;
  }

  if (
    statusFilter &&
    ["ACTIVE", "INACTIVE", "ERROR", "RATE_LIMITED"].includes(statusFilter)
  ) {
    where.status = statusFilter;
  }

  if (languageFilter) {
    where.language = languageFilter;
  }

  if (isOfficialFilter === "true") {
    where.isOfficial = true;
  } else if (isOfficialFilter === "false") {
    where.isOfficial = false;
  }

  // ---- Query sources ----
  const sources = await prisma.source.findMany({
    where: where as any,
    orderBy: [{ name: "asc" }],
    select: {
      id: true,
      name: true,
      websiteUrl: true,
      sourceType: true,
      feedUrl: true,
      apiUrl: true,
      language: true,
      trustScore: true,
      reliabilityScore: true,
      duplicateRate: true,
      clickbaitRate: true,
      isOfficial: true,
      status: true,
      fetchFrequencyMinutes: true,
      lastFetchedAt: true,
      lastFetchStatus: true,
      consecutiveFailures: true,
      lastErrorMessage: true,
      usageNotes: true,
      createdAt: true,
    },
  });

  // ---- Resolve dependent counts + health for each source ----
  const sourcesWithMeta: SourceRow[] = await Promise.all(
    sources.map(async (s) => {
      const [sourceMappingCount, rawArticleCount, storyArticleCount, fetchLogCount] =
        await Promise.all([
          prisma.sourceMapping.count({ where: { sourceId: s.id } }),
          prisma.rawArticle.count({ where: { sourceId: s.id } }),
          prisma.storyArticle.count({ where: { sourceId: s.id } }),
          prisma.fetchLog.count({ where: { sourceId: s.id } }),
        ]);

      return {
        id: s.id,
        name: s.name,
        websiteUrl: s.websiteUrl,
        sourceType: s.sourceType,
        feedUrl: s.feedUrl,
        apiUrl: s.apiUrl,
        language: s.language,
        trustScore: s.trustScore / 10, // 0-100 DB → 1-10 display
        reliabilityScore: s.reliabilityScore,
        duplicateRate: s.duplicateRate,
        clickbaitRate: s.clickbaitRate,
        isOfficial: s.isOfficial,
        status: s.status,
        fetchFrequencyMinutes: s.fetchFrequencyMinutes,
        lastFetchedAt: s.lastFetchedAt,
        lastFetchStatus: s.lastFetchStatus,
        consecutiveFailures: s.consecutiveFailures,
        lastErrorMessage: s.lastErrorMessage,
        usageNotes: s.usageNotes,
        createdAt: s.createdAt,
        health: sourceHealth(s.lastFetchStatus, s.consecutiveFailures),
        dependentCount:
          sourceMappingCount + rawArticleCount + storyArticleCount + fetchLogCount,
      };
    }),
  );

  // ---- Resolve edit source (if editing) ----
  const editSource = editId
    ? await prisma.source.findUnique({
        where: { id: editId },
        select: {
          id: true,
          name: true,
          websiteUrl: true,
          sourceType: true,
          feedUrl: true,
          apiUrl: true,
          language: true,
          trustScore: true,
          reliabilityScore: true,
          duplicateRate: true,
          clickbaitRate: true,
          isOfficial: true,
          status: true,
          fetchFrequencyMinutes: true,
          usageNotes: true,
        },
      })
    : null;

  const editSourceData = editSource
    ? {
        id: editSource.id,
        name: editSource.name,
        websiteUrl: editSource.websiteUrl,
        sourceType: editSource.sourceType,
        feedUrl: editSource.feedUrl,
        apiUrl: editSource.apiUrl,
        language: editSource.language,
        trustScore: editSource.trustScore / 10, // 0-100 DB → 1-10 display
        reliabilityScore: editSource.reliabilityScore,
        duplicateRate: editSource.duplicateRate,
        clickbaitRate: editSource.clickbaitRate,
        isOfficial: editSource.isOfficial,
        status: editSource.status,
        fetchFrequencyMinutes: editSource.fetchFrequencyMinutes,
        usageNotes: editSource.usageNotes,
      }
    : null;

  // ---- Distinct languages for the filter dropdown ----
  const languages = await prisma.source.findMany({
    select: { language: true },
    distinct: ["language"],
    orderBy: { language: "asc" },
  });

  return (
    <SourcesPageClient
      sources={sourcesWithMeta}
      searchQuery={search}
      typeFilter={typeFilter}
      statusFilter={statusFilter}
      languageFilter={languageFilter}
      isOfficialFilter={isOfficialFilter}
      languages={languages.map((l) => l.language)}
      editSource={editSourceData}
      successMsg={successMsg}
      errorMsg={errorMsg}
    />
  );
}
