import "server-only";
import { count } from "drizzle-orm";
import { connection } from "next/server";
import { appDb, schema } from "@/lib/appdb";
import type { SosyalKanitVerisi } from "@/lib/sosyal-kanit-sabitler";

/**
 * Fiyat bölümündeki sosyal kanıt şeridinin sayıları.
 *
 * İki sayı, iki ayrı kaynak — bilerek:
 *
 * 1. "X öğrenci listesini oluşturdu" KENDİ veritabanımızdan gelir (`reports`
 *    tablosu; satır yalnızca liste gerçekten üretildikten sonra yazılır,
 *    bkz. app/sonuc/actions.ts). Bu sayı ziyaretçiye verilen bir söz olduğu
 *    için gerçek olmak zorunda; Rybbit'ten okunsaydı reklam engelleyiciler
 *    yüzünden olduğundan düşük çıkardı.
 * 2. "Şu anda X kişi sitede" yalnızca Rybbit'ten gelebilir: giriş yapmamış
 *    ziyaretçinin bizim veritabanımızda hiçbir izi yok.
 *
 * Rybbit env'i eksikse (dev, anahtar tanımsız) canlı sayı `null` döner ve
 * şeritte o satır hiç çizilmez — asla uydurulmuş sayı gösterilmez.
 */

/** Rybbit'in "şu an sitede" penceresi (GA'nın 30 dakikalık tanımıyla aynı). */
const CANLI_DAKIKA = 30;

const LISTE_TTL_MS = 10 * 60_000;
const CANLI_TTL_MS = 30_000;

const HOST = process.env.RYBBIT_HOST;
const API_KEY = process.env.RYBBIT_API_KEY;
/**
 * DİKKAT: Rybbit'in istatistik API'si SAYISAL site kimliği ister
 * (`/api/sites/:siteId/...` sorgusu ClickHouse'ta `site_id` Int32'ye
 * bağlanıyor). `RYBBIT_SITE_ID` ise script'in kullandığı herkese açık
 * kimlik (f2cb...) — ikisi farklı, birbirinin yerine geçmez.
 */
const STATS_SITE_ID = process.env.RYBBIT_STATS_SITE_ID;

type Kutu<T> = { deger: T; zaman: number };

/**
 * Süreç içi TTL önbelleği. `use cache` yerine bunu kullanıyoruz: derleme
 * anında `data/` boş (bkz. Dockerfile), dolayısıyla prerender edilen bir
 * sayı 0 olarak taşa yazılırdı. `connection()` + bu bellek, sayıyı istek
 * anına taşır ama her ziyaretçide DB/Rybbit'e gitmez. Uygulama tek süreçli
 * standalone olarak çalıştığı için modül belleği yeterli.
 */
const bellek: { liste?: Kutu<number>; canli?: Kutu<number | null> } = {};

/** Üretilmiş tercih listesi sayısı. DB okunamazsa son bilinen değer korunur. */
export async function olusturulanListeSayisi(): Promise<number> {
  await connection();

  const onceki = bellek.liste;
  if (onceki && Date.now() - onceki.zaman < LISTE_TTL_MS) return onceki.deger;

  let deger = onceki?.deger ?? 0;
  try {
    const [satir] = await appDb.select({ n: count() }).from(schema.reports);
    deger = satir?.n ?? 0;
  } catch {
    // Sayı gösterilemezse şerit gizlenir; sayfa asla hata vermez.
  }
  bellek.liste = { deger, zaman: Date.now() };
  return deger;
}

/** Son 30 dakikadaki tekil ziyaretçi. Rybbit yoksa/erişilemezse null. */
export async function anlikZiyaretci(): Promise<number | null> {
  if (!HOST || !API_KEY || !STATS_SITE_ID) return null;

  // `Date.now()`den önce şart: prerender sırasında saat okumak yasak, istek
  // anına bağlanmamız gerekiyor. Kardeş fonksiyondaki `connection()` bunu
  // karşılamıyor — ikisi `Promise.all` ile paralel koşuyor.
  await connection();

  const onceki = bellek.canli;
  if (onceki && Date.now() - onceki.zaman < CANLI_TTL_MS) return onceki.deger;

  let deger: number | null = null;
  try {
    const cevap = await fetch(
      `${HOST}/api/sites/${STATS_SITE_ID}/live-user-count?minutes=${CANLI_DAKIKA}`,
      {
        headers: { Authorization: `Bearer ${API_KEY}` },
        cache: "no-store",
        // Analitik hiçbir koşulda sayfayı bekletmesin
        signal: AbortSignal.timeout(3000),
      },
    );
    if (cevap.ok) {
      const veri = (await cevap.json()) as { count?: number };
      if (typeof veri.count === "number" && Number.isFinite(veri.count)) {
        deger = veri.count;
      }
    }
  } catch {
    // Yut: canlı satır çizilmez, şeridin geri kalanı ayakta kalır.
  }
  bellek.canli = { deger, zaman: Date.now() };
  return deger;
}

export async function sosyalKanitVerisi(): Promise<SosyalKanitVerisi> {
  const [liste, canli] = await Promise.all([
    olusturulanListeSayisi(),
    anlikZiyaretci(),
  ]);
  return { liste, canli };
}