"use server";

import { createHash, randomBytes } from "crypto";
import { ID, Query } from "node-appwrite";
import { redirect } from "next/navigation";

import { createAdminClient } from "./server";
import { DATABASE_ID, TABLES } from "./schema";
import type { AuthState } from "./auth-types";

const TOKEN_EXPIRY_MS = 15 * 60 * 1000;

function generateToken(): { plain: string; hash: string } {
  const chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
  const bytes = randomBytes(8);
  const plain = Array.from(bytes)
    .map((b) => chars[b % chars.length])
    .join("");
  const hash = createHash("sha256").update(plain).digest("hex");
  return { plain, hash };
}

export async function requestPasswordResetAction(
  _prev: AuthState,
  formData: FormData,
): Promise<AuthState> {
  const email = String(formData.get("email") ?? "").trim().toLowerCase();
  if (!email) return { ok: false, error: "Email zorunlu." };

  try {
    const { tablesDB, users, messaging } = createAdminClient();

    const found = await users.list([Query.equal("email", email), Query.limit(1)]);
    // Kullanıcı yoksa hata vermiyoruz — timing attack önlemi
    if (found.total === 0) return { ok: true };

    const user = found.users[0];
    const { plain, hash } = generateToken();
    const expiresAt = new Date(Date.now() + TOKEN_EXPIRY_MS).toISOString();

    await tablesDB.createRow(DATABASE_ID, TABLES.passwordResets, ID.unique(), {
      email,
      userId: user.$id,
      tokenHash: hash,
      expiresAt,
    });

    const appUrl = process.env.APP_URL?.replace(/\/$/, "") ?? "http://localhost:3000";
    const resetLink = `${appUrl}/reset-password?token=${plain}`;

    await messaging.createEmail(
      ID.unique(),
      "Şifre Sıfırlama Kodunuz",
      `<p>Merhaba,</p>
<p>Şifre sıfırlama talebiniz alındı. Aşağıdaki kodu kullanın:</p>
<h2 style="letter-spacing:6px;font-size:32px;">${plain}</h2>
<p>Veya doğrudan linke tıklayın:</p>
<p><a href="${resetLink}">${resetLink}</a></p>
<p style="color:#888;font-size:12px;">Bu kod 15 dakika geçerlidir. Bu talebi siz yapmadıysanız bu e-postayı dikkate almayın.</p>`,
      [],
      [user.$id],
      [],
    );

    return { ok: true };
  } catch {
    return { ok: false, error: "Bir hata oluştu. Tekrar deneyin." };
  }
}

export async function verifyResetToken(
  token: string,
): Promise<{ valid: boolean; tokenId?: string; userId?: string }> {
  if (!token) return { valid: false };

  try {
    const hash = createHash("sha256").update(token.toUpperCase().trim()).digest("hex");
    const { tablesDB } = createAdminClient();

    const result = await tablesDB.listRows({
      databaseId: DATABASE_ID,
      tableId: TABLES.passwordResets,
      queries: [
        Query.equal("tokenHash", hash),
        Query.greaterThan("expiresAt", new Date().toISOString()),
        Query.limit(1),
      ],
    });

    if (result.total === 0) return { valid: false };

    const row = result.rows[0] as unknown as { $id: string; userId: string; usedAt?: string };
    if (row.usedAt) return { valid: false };

    return { valid: true, tokenId: row.$id, userId: row.userId };
  } catch {
    return { valid: false };
  }
}

export async function resetPasswordAction(
  _prev: AuthState,
  formData: FormData,
): Promise<AuthState> {
  const token = String(formData.get("token") ?? "").trim();
  const password = String(formData.get("password") ?? "");
  const confirmPassword = String(formData.get("confirmPassword") ?? "");

  if (!token || !password) return { ok: false, error: "Tüm alanlar zorunlu." };
  if (password.length < 8) return { ok: false, error: "Şifre en az 8 karakter olmalı." };
  if (password !== confirmPassword) return { ok: false, error: "Şifreler eşleşmiyor." };

  const { valid, tokenId, userId } = await verifyResetToken(token);
  if (!valid || !tokenId || !userId) {
    return { ok: false, error: "Kod geçersiz veya süresi dolmuş." };
  }

  try {
    const { tablesDB, users } = createAdminClient();

    await users.updatePassword(userId, password);

    await tablesDB.updateRow(DATABASE_ID, TABLES.passwordResets, tokenId, {
      usedAt: new Date().toISOString(),
    });
  } catch {
    return { ok: false, error: "Şifre güncellenemedi. Tekrar deneyin." };
  }

  redirect("/sign-in?reset=success");
}
