'use server';
import { redirect } from 'next/navigation';
import { headers, cookies } from 'next/headers';
import { rateLimit, clientIp } from '@/lib/http';
import { z } from 'zod';
import { prisma } from '@/lib/db';
import { createSession, destroySession, hashPassword, verifyPassword, currentUser } from '@/lib/auth';
import { issueToken, consumeToken } from '@/lib/tokens';
import { sendEmail, mailConfigured } from '@/lib/notify';
import { verifyEmail, resetEmail, passwordChangedEmail } from '@/lib/emails';
import { log } from '@/lib/http';

const base = async () => process.env.APP_URL || `https://${(await headers()).get('host')}`;
async function sendVerification(u: { id: string; email: string; name: string }) {
  const raw = await issueToken(u.id, 'verify');
  const m = verifyEmail(u.name, `${await base()}/dogrula?token=${raw}`);
  await sendEmail(u.email, m.subject, m.html, m.text);
}

export type FormState = { error?: string } | undefined;

export async function login(_: FormState, fd: FormData): Promise<FormState> {
  const email = String(fd.get('email') || '').trim().toLowerCase();
  const ip = clientIp(await headers());
  if (!await rateLimit(`login:${ip}`, 10, 10 * 60_000) || !await rateLimit(`login:${email}`, 8, 10 * 60_000)) return { error: 'Çok fazla deneme. 10 dakika sonra tekrar deneyin.' };
  const u = await prisma.user.findUnique({ where: { email } });
  if (!u || !(await verifyPassword(String(fd.get('password') || ''), u.passwordHash))) return { error: 'E-posta veya şifre hatalı.' };
  if (u.disabledAt) return { error: 'Hesabınız askıya alındı. Destek için bizimle iletişime geçin.' };
  await createSession(u.id, u.sessionVersion);
  const next = String(fd.get('sonra') || '');
  redirect(/^\/panel(\/[\w/?=&%.-]*)?$/.test(next) ? next : u.role === 'ADMIN' ? '/krtf1krtf' : '/panel');
}

const Reg = z.object({ name: z.string().min(2, 'Adınızı yazın'), email: z.string().email('Geçerli bir e-posta yazın'), password: z.string().min(8, 'Şifre en az 8 karakter olmalı'), company: z.string().optional() });
export async function register(_: FormState, fd: FormData): Promise<FormState> {
  if (!await rateLimit(`reg:${clientIp(await headers())}`, 5, 60 * 60_000)) return { error: 'Çok fazla kayıt denemesi.' };
  const r = Reg.safeParse(Object.fromEntries(fd));
  if (!r.success) return { error: r.error.issues[0].message };
  const email = r.data.email.toLowerCase();
  if (await prisma.user.findUnique({ where: { email } })) return { error: 'Bu e-posta ile kayıtlı bir hesap var.' };
  const isAdmin = !!process.env.ADMIN_EMAIL && process.env.ADMIN_EMAIL.toLowerCase() === email;
  const u = await prisma.user.create({ data: { name: r.data.name, email, company: r.data.company || null, passwordHash: await hashPassword(r.data.password), role: isAdmin ? 'ADMIN' : 'USER',
    // E-posta servisi yapılandırılmamışsa doğrulama zorunlu tutulamaz (bağlantı gönderilemez) — hesap doğrulanmış sayılır.
    emailVerifiedAt: emailVerificationEnabled() ? null : new Date(), refCode: newRefCode(),
    referredById: await referrerFromCookie() } });
  if (emailVerificationEnabled()) await sendVerification(u).catch((e) => log('error', 'verify_mail_failed', { err: (e as Error).message }));
  await createSession(u.id, u.sessionVersion);
  const paket = String(fd.get('paket') || '');
  const next = String(fd.get('sonra') || '');
  redirect(/^\/panel(\/[\w/?=&%.-]*)?$/.test(next) ? next : paket ? `/panel/yeni?paket=${paket}` : '/panel/yeni');
}

// mail gönderilebiliyorsa yeni kayıtlar e-postasını doğrular (mevcut hesaplar zaten doğrulanmış sayılır)
function emailVerificationEnabled() { return (mailConfigured() && process.env.REQUIRE_EMAIL_VERIFICATION !== '0') || process.env.REQUIRE_EMAIL_VERIFICATION === '1'; }

export async function logout() { await destroySession(); redirect('/'); }

/** Doğrulama e-postasını yeniden gönderir (kullanıcı başına 3 / saat). */
export async function resendVerification(): Promise<{ error?: string; ok?: boolean }> {
  const u = await currentUser();
  if (!u) return { error: 'Giriş gerekli.' };
  if (u.emailVerifiedAt) return { ok: true };
  if (!await rateLimit(`verify:${u.id}`, 3, 60 * 60_000)) return { error: 'Birkaç dakika sonra tekrar deneyin.' };
  await sendVerification(u);
  return { ok: true };
}

const GENERIC = 'Bu adrese kayıtlı bir hesap varsa, birkaç dakika içinde şifre sıfırlama bağlantısı gelecek.';
/** Şifre sıfırlama talebi. Hesap var/yok bilgisini sızdırmaz; IP ve e-posta bazında sınırlıdır. */
export async function requestReset(_: { error?: string; ok?: string } | undefined, fd: FormData): Promise<{ error?: string; ok?: string }> {
  const email = String(fd.get('email') || '').trim().toLowerCase();
  if (!z.string().email().safeParse(email).success) return { error: 'Geçerli bir e-posta yazın.' };
  const ip = clientIp(await headers());
  if (!await rateLimit(`reset-ip:${ip}`, 10, 60 * 60_000) || !await rateLimit(`reset-mail:${email}`, 3, 60 * 60_000)) return { ok: GENERIC };
  const u = await prisma.user.findUnique({ where: { email } });
  if (u) {
    const raw = await issueToken(u.id, 'reset');
    const m = resetEmail(u.name, `${await base()}/sifre-sifirla?token=${raw}`);
    await sendEmail(u.email, m.subject, m.html, m.text).catch((e) => log('error', 'reset_mail_failed', { err: (e as Error).message }));
  }
  return { ok: GENERIC };
}

export async function resetPassword(_: FormState, fd: FormData): Promise<FormState> {
  const token = String(fd.get('token') || '');
  const pw = String(fd.get('password') || ''), pw2 = String(fd.get('password2') || '');
  if (pw.length < 8) return { error: 'Şifre en az 8 karakter olmalı.' };
  if (pw !== pw2) return { error: 'Şifreler aynı değil.' };
  if (!await rateLimit(`reset-do:${clientIp(await headers())}`, 20, 60 * 60_000)) return { error: 'Çok fazla deneme.' };
  const userId = await consumeToken(token, 'reset');
  if (!userId) return { error: 'Bağlantının süresi dolmuş ya da daha önce kullanılmış. Yeni bir bağlantı isteyin.' };
  const u = await prisma.user.update({ where: { id: userId }, data: { passwordHash: await hashPassword(pw), sessionVersion: { increment: 1 }, emailVerifiedAt: undefined } });
  // sıfırlama bağlantısı e-postaya gittiği için adres de doğrulanmış sayılır
  if (!u.emailVerifiedAt) await prisma.user.update({ where: { id: u.id }, data: { emailVerifiedAt: new Date() } });
  await prisma.authToken.updateMany({ where: { userId, type: 'reset', usedAt: null }, data: { usedAt: new Date() } });
  const m = passwordChangedEmail(u.name); await sendEmail(u.email, m.subject, m.html, m.text).catch(() => {});
  await createSession(u.id, u.sessionVersion);
  redirect('/panel?sifre=degisti');
}

/** Oturum açıkken şifre değiştirme: mevcut şifre doğrulanır, diğer oturumlar düşer, bu oturum yenilenir. */
export async function changePassword(_: { error?: string; ok?: string } | undefined, fd: FormData): Promise<{ error?: string; ok?: string }> {
  const me = await currentUser(); if (!me) return { error: 'Oturum bulunamadı, tekrar giriş yapın.' };
  if (!await rateLimit(`pwchg:${me.id}`, 10, 60 * 60_000)) return { error: 'Çok fazla deneme, biraz sonra tekrar deneyin.' };
  const cur = String(fd.get('current') || ''), pw = String(fd.get('password') || ''), pw2 = String(fd.get('password2') || '');
  const u = await prisma.user.findUnique({ where: { id: me.id } });
  if (!u || !await verifyPassword(cur, u.passwordHash)) return { error: 'Mevcut şifre yanlış.' };
  if (pw.length < 8) return { error: 'Yeni şifre en az 8 karakter olmalı.' };
  if (pw !== pw2) return { error: 'Yeni şifreler aynı değil.' };
  const up = await prisma.user.update({ where: { id: u.id }, data: { passwordHash: await hashPassword(pw), sessionVersion: { increment: 1 } } });
  const m = passwordChangedEmail(up.name); await sendEmail(up.email, m.subject, m.html, m.text).catch(() => {});
  await createSession(up.id, up.sessionVersion);
  return { ok: 'Şifreniz değişti. Diğer cihazlardaki oturumlar kapatıldı.' };
}

function newRefCode() { return Array.from(crypto.getRandomValues(new Uint8Array(6)), (b) => 'ABCDEFGHJKLMNPRSTUVYZ23456789'[b % 29]).join(''); }
async function referrerFromCookie() {
  const code = (await cookies()).get('ps_ref')?.value;
  if (!code || !/^[A-Z0-9]{4,12}$/.test(code)) return null;
  return (await prisma.user.findUnique({ where: { refCode: code }, select: { id: true } }))?.id ?? null;
}
