'use server';
import { revalidatePath } from 'next/cache';
import { z } from 'zod';
import { prisma } from '@/lib/db';
import { requireAdmin } from '@/lib/auth';
import { audit } from '@/lib/admin';
import { enqueueOrder } from '@/lib/orders';
import { issueToken } from '@/lib/tokens';
import { sendEmail } from '@/lib/notify';
import { resetEmail, verifyEmail } from '@/lib/emails';
import { log } from '@/lib/http';

export type ActionResult = { ok?: string; error?: string } | undefined;
const id = (fd: FormData, k = 'id') => z.string().min(5).max(40).parse(String(fd.get(k) || ''));
const done = (paths: string[], ok: string): ActionResult => { for (const p of paths) revalidatePath(p); return { ok }; };
const base = () => process.env.APP_URL || '';

// ---------------- siparişler ----------------

/** Teslim edilmiş, başarısız ya da iptal siparişi ücretsiz yeniden üretime alır (kredi düşmez). */
export async function rerenderOrder(_: ActionResult, fd: FormData): Promise<ActionResult> {
  const a = await requireAdmin(); const oid = id(fd);
  const o = await prisma.order.findUnique({ where: { id: oid } });
  if (!o) return { error: 'Sipariş bulunamadı' };
  if (['QUEUED', 'RENDERING'].includes(o.status)) return { error: 'Sipariş zaten kuyrukta ya da üretimde' };
  if (o.status === 'PENDING_PAYMENT') return { error: 'Ödenmemiş sipariş yeniden üretilemez' };
  await prisma.order.update({ where: { id: oid }, data: { status: 'PAID', claimedBy: null } });
  await enqueueOrder(oid);
  await audit(a, 'order.rerender', 'order', oid, { from: o.status, code: o.code });
  return done([`/krtf1krtf/siparisler/${oid}`, '/krtf1krtf/siparisler', '/krtf1krtf'], 'Sipariş kuyruğa alındı');
}

/** Siparişi iptal eder. Kredisi düşülmüş ama henüz üretilmemiş siparişte istenirse 1 kredi iade edilir. */
export async function cancelOrder(_: ActionResult, fd: FormData): Promise<ActionResult> {
  const a = await requireAdmin(); const oid = id(fd); const refund = fd.get('refund') === 'on';
  const r = await prisma.$transaction(async (tx) => {
    const o = await tx.order.findUnique({ where: { id: oid } });
    if (!o) return { error: 'Sipariş bulunamadı' };
    if (['DELIVERED', 'CANCELLED', 'RENDERING'].includes(o.status)) return { error: o.status === 'RENDERING' ? 'Üretimdeki sipariş iptal edilemez; bitmesini bekleyin' : 'Bu sipariş iptal edilemez' };
    // kredi yalnızca ödenmiş ve iadesi yapılmamış siparişlerde iade edilir (FAILED'da worker zaten iade eder)
    const canRefund = ['PAID', 'QUEUED'].includes(o.status);
    const upd = await tx.order.updateMany({ where: { id: oid, status: o.status }, data: { status: 'CANCELLED', progressMsg: 'Yönetici iptal etti' } });
    if (!upd.count) return { error: 'Sipariş durumu değişti, sayfayı yenileyin' };
    await tx.job.updateMany({ where: { orderId: oid, status: { in: ['queued', 'external'] } }, data: { status: 'cancelled' } });
    if (refund && canRefund) await tx.user.update({ where: { id: o.userId }, data: { credits: { increment: 1 } } });
    await audit(a, 'order.cancel', 'order', oid, { from: o.status, code: o.code, refunded: refund && canRefund }, tx);
    return { ok: refund && canRefund ? 'İptal edildi, 1 kredi iade edildi' : 'İptal edildi' };
  });
  if (r.error) return r;
  return done([`/krtf1krtf/siparisler/${oid}`, '/krtf1krtf/siparisler', '/krtf1krtf'], r.ok!);
}

/** Harici ajanın sahiplendiği siparişi bırakır; iç işçi yeniden alabilir. */
export async function releaseClaim(_: ActionResult, fd: FormData): Promise<ActionResult> {
  const a = await requireAdmin(); const oid = id(fd);
  const o = await prisma.order.findUnique({ where: { id: oid } });
  if (!o?.claimedBy) return { error: 'Sipariş sahiplenilmemiş' };
  await prisma.$transaction([
    prisma.order.update({ where: { id: oid }, data: { claimedBy: null, status: 'QUEUED', progress: 0, progressMsg: 'Kuyrukta' } }),
    prisma.job.updateMany({ where: { orderId: oid, status: 'external' }, data: { status: 'queued', lockedBy: null, lockedAt: null, runAfter: new Date() } }),
  ]);
  await audit(a, 'order.release', 'order', oid, { agent: o.claimedBy, code: o.code });
  return done([`/krtf1krtf/siparisler/${oid}`, '/krtf1krtf/kuyruk'], 'Sahiplik bırakıldı, iç işçi alacak');
}

export async function shareOff(_: ActionResult, fd: FormData): Promise<ActionResult> {
  const a = await requireAdmin(); const oid = id(fd);
  await prisma.order.update({ where: { id: oid }, data: { shareToken: null } });
  await audit(a, 'order.share_off', 'order', oid);
  return done([`/krtf1krtf/siparisler/${oid}`], 'Paylaşım bağlantısı kapatıldı');
}

/** Ölü kuyruktaki işi yeniden dener (yeni iş, deneme sayacı sıfır). */
export async function retryJob(_: ActionResult, fd: FormData): Promise<ActionResult> {
  const a = await requireAdmin(); const jid = id(fd);
  const j = await prisma.job.findUnique({ where: { id: jid } });
  if (!j || !['dead', 'failed'].includes(j.status)) return { error: 'İş ölü kuyrukta değil' };
  await prisma.order.update({ where: { id: j.orderId }, data: { status: 'PAID' } });
  await enqueueOrder(j.orderId);
  await audit(a, 'job.retry', 'job', jid, { orderId: j.orderId });
  return done(['/krtf1krtf/kuyruk', `/krtf1krtf/siparisler/${j.orderId}`], 'İş yeniden kuyruğa alındı');
}

// ---------------- kullanıcılar ----------------

/** Kredi ekler (+) ya da düşer (−). Ücretsiz tanım olarak ödeme geçmişine 0 TL kayıt düşülür. */
export async function adjustCredits(_: ActionResult, fd: FormData): Promise<ActionResult> {
  const a = await requireAdmin(); const uid = id(fd);
  const p = z.object({ delta: z.coerce.number().int().min(-500).max(500).refine((x) => x !== 0, 'Sıfır olamaz'), note: z.string().trim().min(2, 'Kısa bir not yazın').max(120) })
    .safeParse({ delta: fd.get('delta'), note: fd.get('note') });
  if (!p.success) return { error: p.error.issues[0].message };
  const { delta, note } = p.data;
  const r = await prisma.$transaction(async (tx) => {
    const u = delta < 0
      ? await tx.user.updateMany({ where: { id: uid, credits: { gte: -delta } }, data: { credits: { increment: delta } } })
      : await tx.user.updateMany({ where: { id: uid }, data: { credits: { increment: delta } } });
    if (!u.count) return { error: delta < 0 ? 'Kullanıcının bu kadar kredisi yok' : 'Kullanıcı bulunamadı' };
    await tx.payment.create({ data: { userId: uid, plan: 'admin', credits: delta, amount: 0, status: 'succeeded' } });
    await audit(a, 'user.credits', 'user', uid, { delta, note }, tx);
    return { ok: `${delta > 0 ? '+' : ''}${delta} kredi işlendi` };
  });
  if (r.error) return r;
  log('info', 'admin_credit', { by: a.email, userId: uid, delta });
  return done([`/krtf1krtf/kullanicilar/${uid}`, '/krtf1krtf/kullanicilar'], r.ok!);
}

export async function markVerified(_: ActionResult, fd: FormData): Promise<ActionResult> {
  const a = await requireAdmin(); const uid = id(fd);
  await prisma.user.update({ where: { id: uid }, data: { emailVerifiedAt: new Date() } });
  await audit(a, 'user.verify', 'user', uid);
  return done([`/krtf1krtf/kullanicilar/${uid}`], 'E-posta doğrulanmış işaretlendi');
}

export async function sendVerify(_: ActionResult, fd: FormData): Promise<ActionResult> {
  const a = await requireAdmin(); const uid = id(fd);
  const u = await prisma.user.findUnique({ where: { id: uid } });
  if (!u) return { error: 'Kullanıcı bulunamadı' };
  if (u.emailVerifiedAt) return { error: 'E-posta zaten doğrulanmış' };
  const m = verifyEmail(u.name, `${base()}/dogrula?token=${await issueToken(u.id, 'verify')}`);
  await sendEmail(u.email, m.subject, m.html, m.text);
  await audit(a, 'user.send_verify', 'user', uid);
  return done([`/krtf1krtf/kullanicilar/${uid}`], 'Doğrulama e-postası gönderildi');
}

export async function sendReset(_: ActionResult, fd: FormData): Promise<ActionResult> {
  const a = await requireAdmin(); const uid = id(fd);
  const u = await prisma.user.findUnique({ where: { id: uid } });
  if (!u) return { error: 'Kullanıcı bulunamadı' };
  const m = resetEmail(u.name, `${base()}/sifre-sifirla?token=${await issueToken(u.id, 'reset')}`);
  await sendEmail(u.email, m.subject, m.html, m.text);
  await audit(a, 'user.send_reset', 'user', uid);
  return done([`/krtf1krtf/kullanicilar/${uid}`], 'Şifre sıfırlama e-postası gönderildi');
}

export async function logoutAll(_: ActionResult, fd: FormData): Promise<ActionResult> {
  const a = await requireAdmin(); const uid = id(fd);
  if (uid === a.id) return { error: 'Kendi oturumlarınızı Hesap sayfasından şifre değiştirerek kapatın' };
  await prisma.user.update({ where: { id: uid }, data: { sessionVersion: { increment: 1 } } });
  await audit(a, 'user.logout', 'user', uid);
  return done([`/krtf1krtf/kullanicilar/${uid}`], 'Tüm oturumlar kapatıldı');
}

export async function setRole(_: ActionResult, fd: FormData): Promise<ActionResult> {
  const a = await requireAdmin(); const uid = id(fd);
  const role = fd.get('role') === 'ADMIN' ? 'ADMIN' : 'USER';
  if (uid === a.id) return { error: 'Kendi rolünüzü değiştiremezsiniz' };
  await prisma.user.update({ where: { id: uid }, data: { role, sessionVersion: { increment: 1 } } });
  await audit(a, 'user.role', 'user', uid, { role });
  return done([`/krtf1krtf/kullanicilar/${uid}`, '/krtf1krtf/kullanicilar'], role === 'ADMIN' ? 'Yönetici yapıldı' : 'Kullanıcı rolüne alındı');
}

export async function setSuspended(_: ActionResult, fd: FormData): Promise<ActionResult> {
  const a = await requireAdmin(); const uid = id(fd); const on = fd.get('on') === '1';
  if (uid === a.id) return { error: 'Kendi hesabınızı askıya alamazsınız' };
  await prisma.user.update({ where: { id: uid }, data: on ? { disabledAt: new Date(), sessionVersion: { increment: 1 } } : { disabledAt: null } });
  await audit(a, on ? 'user.suspend' : 'user.unsuspend', 'user', uid, { reason: String(fd.get('reason') || '').slice(0, 120) || undefined });
  return done([`/krtf1krtf/kullanicilar/${uid}`, '/krtf1krtf/kullanicilar'], on ? 'Hesap askıya alındı' : 'Askı kaldırıldı');
}
