"use server";

import { and, eq, sql } from "drizzle-orm";
import { getSession, getCurrentUser } from "@/lib/session";
import { appDb, schema } from "@/lib/appdb";
import { kullanicininRaporu } from "@/features/rapor/rapor-queries";
import { PUAN_TURLERI, type PuanTuruKey } from "@/types/yokatlas";
import {
  spendCredits,
  grantCredits,
  krediBittiIsaretle,
  RAPOR_KREDI,
  MAX_REVIZYON,
} from "@/lib/credits";
import {
  raporUret,
  listeOzetiCikar,
  RaporUretimHatasi,
} from "@/lib/ai/rapor";
import type {
  RaporParams,
  RaporSonuc,
} from "@/features/rapor/types/rapor";
import { sihirbazDogrula, type SihirbazSecimleri } from "@/features/sihirbaz/sihirbaz-sabitler";
import { raporMaskele } from "@/lib/rapor-maske";


// Modal yerinde render ettiği için action redirect etmez; sonucu döner.
export type ListeSonuc =
  | {
      ok: true;
      rapor: RaporSonuc;
      params: RaporParams;
      revisionCount: number;
      kredi: number;
      hasPaket: boolean;
    }
  | { ok: false; error: string; code: "AUTH" | "PAKET" | "KREDI" | "HATA" };

function siraTurGecerli(sira: number, tur: string): tur is PuanTuruKey {
  return (
    Number.isFinite(sira) && sira >= 1 && sira <= 4_000_000 && tur in PUAN_TURLERI
  );
}

function aiHataMesaji(err: unknown): string {
  if (err instanceof RaporUretimHatasi) return err.message;
  // AbortSignal.timeout: DOMException "TimeoutError"; SDK'lar abort'u kendi
  // hata sınıflarıyla sarabiliyor (ör. APIUserAbortError) ve openai/anthropic
  // bu sınıflarda .name'i "Error" bırakıyor — ada ek olarak sınıf adına ve
  // mesaja da bak ("Request was aborted." / "Request timed out.").
  if (
    err instanceof Error &&
    /abort|timeout|timed out/i.test(
      `${err.name} ${err.constructor.name} ${err.message}`,
    )
  ) {
    return "Liste üretimi bu sefer çok uzun sürdü ve durduruldu; harcanan kredin otomatik iade edildi. Tekrar dener misin?";
  }
  if (err instanceof Error && err.message === "AI_KEY_MISSING") {
    // Yapılandırma detayı log'a; kullanıcıya altyapı sızdırmayan mesaj
    console.error("[liste] Yapay Zeka anahtarı eksik — üretim başlatılamadı");
    return "Liste üretimi şu anda başlatılamıyor. Birazdan tekrar dener misin? Harcanan kredin otomatik iade edilir.";
  }
  console.error("[liste] üretim hatası:", err);
  return "Liste üretilirken bir sorun oluştu. Birazdan tekrar dener misin?";
}

function paramsBirlestir(
  sira: number,
  tur: PuanTuruKey,
  secimler: SihirbazSecimleri,
): RaporParams {
  return {
    sira: Math.round(sira),
    tur,
    kategoriler: secimler.kategoriler,
    iller: secimler.iller,
    universiteTipi: secimler.universiteTipi,
    oncelikler: secimler.oncelikler,
  };
}

export async function listeOlustur(input: {
  sira: number;
  tur: string;
  secimler: unknown;
  requestId: string;
}): Promise<ListeSonuc> {
  const session = await getSession();
  if (!session) {
    return { ok: false, code: "AUTH", error: "Giriş yapmalısın." };
  }
  const user = await getCurrentUser();
  if (!user) {
    return { ok: false, code: "AUTH", error: "Giriş yapmalısın." };
  }
  // Paket şartı yok: üretim kredi bazlı (yeni kullanıcının 5 deneme kredisi
  // burada yanmaya başlar). Paketsize dönen rapor maskelenir.

  if (!siraTurGecerli(input.sira, input.tur)) {
    return { ok: false, code: "HATA", error: "Geçerli bir sıralama gerekli." };
  }
  const secimler = sihirbazDogrula(input.secimler);
  if (!secimler) {
    return {
      ok: false,
      code: "HATA",
      error: "En az bir ilgi alanı seçmelisin.",
    };
  }
  if (!input.requestId || typeof input.requestId !== "string") {
    return { ok: false, code: "HATA", error: "Geçersiz istek." };
  }

  const params = paramsBirlestir(input.sira, input.tur, secimler);

  // 3 kredi düş (idempotent: aynı requestId ile retry çifte harcamaz)
  const harcama = await spendCredits({
    userId: user.id,
    amount: RAPOR_KREDI,
    reason: "report_generate",
    refId: input.requestId,
  });
  if (!harcama.ok) {
    if (harcama.error === "INSUFFICIENT") {
      await krediBittiIsaretle(user.id);
      return {
        ok: false,
        code: "KREDI",
        error: `Liste oluşturmak için ${RAPOR_KREDI} kredi gerekli.`,
      };
    }
    // DUPLICATE: bu requestId zaten işlendi. Önceki deneme başarısız olup
    // iade edildiyse mevcut (eski) raporu yeniymiş gibi döndürme; taze bir
    // requestId ile yeniden denemesini iste.
    const iade = await appDb.query.creditLedger.findFirst({
      where: and(
        eq(schema.creditLedger.reason, "refund"),
        eq(schema.creditLedger.refId, input.requestId),
      ),
    });
    if (iade) {
      return {
        ok: false,
        code: "HATA",
        error:
          "Önceki denemen başarısız olduğu için kredin iade edilmişti. Tekrar dener misin?",
      };
    }
    const mevcut = await kullanicininRaporu(user.id);
    if (mevcut?.result) {
      const rapor = mevcut.result as RaporSonuc;
      return {
        ok: true,
        rapor: user.hasPaket ? rapor : raporMaskele(rapor),
        params: mevcut.params as RaporParams,
        revisionCount: mevcut.revisionCount,
        kredi: user.creditBalance,
        hasPaket: user.hasPaket,
      };
    }
    return { ok: false, code: "HATA", error: "İstek tekrarlandı." };
  }

  let sonuc: RaporSonuc;
  try {
    sonuc = await raporUret(params);
  } catch (err) {
    // Üretim başarısız → krediyi iade et
    await grantCredits({
      userId: user.id,
      delta: RAPOR_KREDI,
      reason: "refund",
      refId: input.requestId,
    }).catch(() => {});
    return { ok: false, code: "HATA", error: aiHataMesaji(err) };
  }

  const now = new Date();
  await appDb
    .insert(schema.reports)
    .values({
      id: crypto.randomUUID(),
      userId: user.id,
      params,
      result: sonuc,
      revisionCount: 0,
      createdAt: now,
      updatedAt: now,
    })
    .onConflictDoUpdate({
      target: schema.reports.userId,
      set: { params, result: sonuc, revisionCount: 0, updatedAt: now },
    });

  return {
    ok: true,
    rapor: user.hasPaket ? sonuc : raporMaskele(sonuc),
    params,
    revisionCount: 0,
    kredi: user.creditBalance - RAPOR_KREDI,
    hasPaket: user.hasPaket,
  };
}

export async function listeRevize(input: {
  feedback: string;
  requestId: string;
}): Promise<ListeSonuc> {
  const session = await getSession();
  if (!session) return { ok: false, code: "AUTH", error: "Giriş yapmalısın." };
  const user = await getCurrentUser();
  if (!user) return { ok: false, code: "AUTH", error: "Giriş yapmalısın." };
  if (!user.hasPaket) return { ok: false, code: "PAKET", error: "Paket gerekli." };

  const feedback = (input.feedback ?? "").trim();
  if (feedback.length < 5) {
    return {
      ok: false,
      code: "HATA",
      error: "Ne değişsin istediğini kısaca yazmalısın.",
    };
  }
  if (!input.requestId) {
    return { ok: false, code: "HATA", error: "Geçersiz istek." };
  }

  const rapor = await kullanicininRaporu(user.id);
  if (!rapor?.result) {
    return { ok: false, code: "HATA", error: "Önce bir liste oluşturmalısın." };
  }
  if (rapor.revisionCount >= MAX_REVIZYON) {
    return {
      ok: false,
      code: "HATA",
      error: `Revizyon hakkın doldu (en fazla ${MAX_REVIZYON}).`,
    };
  }

  const params = rapor.params as RaporParams;
  const onceki = rapor.result as RaporSonuc;

  const harcama = await spendCredits({
    userId: user.id,
    amount: RAPOR_KREDI,
    reason: "report_revision",
    refId: input.requestId,
  });
  if (!harcama.ok) {
    if (harcama.error === "INSUFFICIENT") {
      await krediBittiIsaretle(user.id);
      return {
        ok: false,
        code: "KREDI",
        error: `Revizyon için ${RAPOR_KREDI} kredi gerekli.`,
      };
    }
    // DUPLICATE: bu requestId zaten işlendi. İade varsa önceki deneme
    // başarısızdı → taze bir denemeye yönlendir. Yoksa revizyon tamamlanmış
    // ama cevap istemciye ulaşmamıştır → güncel raporu döndür.
    const iade = await appDb.query.creditLedger.findFirst({
      where: and(
        eq(schema.creditLedger.reason, "refund"),
        eq(schema.creditLedger.refId, input.requestId),
      ),
    });
    if (iade) {
      return {
        ok: false,
        code: "HATA",
        error:
          "Önceki denemen başarısız olduğu için kredin iade edilmişti. Tekrar dener misin?",
      };
    }
    const guncel = await kullanicininRaporu(user.id);
    if (guncel?.result) {
      return {
        ok: true,
        rapor: guncel.result as RaporSonuc,
        params: guncel.params as RaporParams,
        revisionCount: guncel.revisionCount,
        kredi: user.creditBalance,
        hasPaket: true,
      };
    }
    return { ok: false, code: "HATA", error: "İstek tekrarlandı." };
  }

  let sonuc: RaporSonuc;
  try {
    sonuc = await raporUret(
      params,
      feedback.slice(0, 1000),
      listeOzetiCikar(onceki, params.sira),
    );
  } catch (err) {
    await grantCredits({
      userId: user.id,
      delta: RAPOR_KREDI,
      reason: "refund",
      refId: input.requestId,
    }).catch(() => {});
    return { ok: false, code: "HATA", error: aiHataMesaji(err) };
  }

  // Sayaç yalnızca başarılı üretimde artar
  await appDb
    .update(schema.reports)
    .set({
      result: sonuc,
      revisionCount: sql`${schema.reports.revisionCount} + 1`,
      updatedAt: new Date(),
    })
    .where(eq(schema.reports.id, rapor.id));

  return {
    ok: true,
    rapor: sonuc,
    params,
    revisionCount: rapor.revisionCount + 1,
    kredi: user.creditBalance - RAPOR_KREDI,
    hasPaket: true,
  };
}
