"use server";

import { db } from "@/lib/db";
import bcrypt from "bcryptjs";
import { signIn, signOut, auth } from "@/auth";
import { AuthError } from "next-auth";
import { redirect } from "next/navigation";
import { sendWelcomeEmail, sendVerificationEmail, sendPasswordResetEmail } from "@/lib/mail";

export type ActionResult = { error?: string; success?: string };

// ─── Register ─────────────────────────────────────────────────────────────────

export async function registerAction(
  _prev: ActionResult,
  formData: FormData
): Promise<ActionResult> {
  const name = String(formData.get("name") ?? "").trim();
  const email = String(formData.get("email") ?? "").toLowerCase().trim();
  const password = String(formData.get("password") ?? "");

  if (!name || !email || !password) {
    return { error: "All fields are required." };
  }
  if (password.length < 8) {
    return { error: "Password must be at least 8 characters." };
  }
  // Basic email format validation
  if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
    return { error: "Invalid email address." };
  }

  const existing = await db.user.findUnique({ where: { email } });
  if (existing) {
    return { error: "An account with this email already exists." };
  }

  const hashedPassword = await bcrypt.hash(password, 12);
  const verifyToken = crypto.randomUUID();

  await db.user.create({
    data: { name, email, password: hashedPassword, verifyToken },
  });

  // Fire emails — non-blocking
  sendWelcomeEmail(email, name).catch(() => {});
  sendVerificationEmail(email, name, verifyToken).catch(() => {});

  // Sign in immediately after registration
  try {
    await signIn("credentials", { email, password, redirect: false });
  } catch {
    // If auto-login fails, redirect to login
    redirect("/login?registered=1");
  }

  redirect("/dashboard");
}

// ─── Login ────────────────────────────────────────────────────────────────────

export async function loginAction(
  _prev: ActionResult,
  formData: FormData
): Promise<ActionResult> {
  const email = String(formData.get("email") ?? "").toLowerCase().trim();
  const password = String(formData.get("password") ?? "");
  // Only allow internal paths for `next` redirect
  const nextRaw = String(formData.get("next") ?? "").trim();
  const redirectTo = nextRaw.startsWith("/") && !nextRaw.startsWith("//") ? nextRaw : "/dashboard";

  if (!email || !password) {
    return { error: "Email and password are required." };
  }

  try {
    await signIn("credentials", {
      email,
      password,
      redirectTo,
    });
  } catch (error) {
    if (error instanceof AuthError) {
      switch (error.type) {
        case "CredentialsSignin":
          return { error: "Invalid email or password." };
        default:
          return { error: "Something went wrong. Please try again." };
      }
    }
    throw error; // Let Next.js handle redirects
  }

  return {};
}

// ─── Logout ───────────────────────────────────────────────────────────────────

export async function logoutAction() {
  await signOut({ redirectTo: "/login" });
}

// ─── Forgot Password ──────────────────────────────────────────────────────────

export async function forgotPasswordAction(
  _prev: ActionResult,
  formData: FormData
): Promise<ActionResult> {
  const email = String(formData.get("email") ?? "").toLowerCase().trim();
  if (!email) return { error: "Email is required." };

  const user = await db.user.findUnique({ where: { email } });
  // Always return success to prevent email enumeration
  if (!user) {
    return { success: "If that email exists, a reset link has been sent." };
  }

  const token = crypto.randomUUID();
  const expiry = new Date(Date.now() + 60 * 60 * 1000); // 1 hour

  await db.user.update({
    where: { email },
    data: { resetToken: token, resetTokenExpiry: expiry },
  });

  sendPasswordResetEmail(email, token).catch(() => {});

  return { success: "If that email exists, a reset link has been sent." };
}

// ─── Reset Password ───────────────────────────────────────────────────────────

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

  if (!token) return { error: "Invalid reset link." };
  if (password.length < 8) return { error: "Password must be at least 8 characters." };
  if (password !== confirm) return { error: "Passwords do not match." };

  const user = await db.user.findUnique({ where: { resetToken: token } });
  if (!user || !user.resetTokenExpiry || user.resetTokenExpiry < new Date()) {
    return { error: "Reset link is invalid or has expired." };
  }

  const hashed = await bcrypt.hash(password, 12);
  await db.user.update({
    where: { id: user.id },
    data: { password: hashed, resetToken: null, resetTokenExpiry: null },
  });

  redirect("/login?reset=1");
}

// ─── Update Profile ───────────────────────────────────────────────────────────

export async function updateProfileAction(
  _prev: ActionResult,
  formData: FormData
): Promise<ActionResult> {
  const session = await auth();
  if (!session?.user?.id) return { error: "Not authenticated." };

  const name = String(formData.get("name") ?? "").trim();
  const phone = String(formData.get("phone") ?? "").trim();

  if (!name) return { error: "Name is required." };

  await db.user.update({
    where: { id: session.user.id },
    data: { name, phone: phone || null },
  });

  return { success: "Profile updated successfully." };
}

// ─── Change Password ──────────────────────────────────────────────────────────

export async function changePasswordAction(
  _prev: ActionResult,
  formData: FormData
): Promise<ActionResult> {
  const session = await auth();
  if (!session?.user?.id) return { error: "Not authenticated." };

  const current = String(formData.get("currentPassword") ?? "");
  const next = String(formData.get("newPassword") ?? "");
  const confirm = String(formData.get("confirmPassword") ?? "");

  if (!current || !next || !confirm) return { error: "All fields are required." };
  if (next.length < 8) return { error: "New password must be at least 8 characters." };
  if (next !== confirm) return { error: "Passwords do not match." };

  const user = await db.user.findUnique({ where: { id: session.user.id } });
  if (!user?.password) return { error: "Cannot change password for this account." };

  const match = await bcrypt.compare(current, user.password);
  if (!match) return { error: "Current password is incorrect." };

  const hashed = await bcrypt.hash(next, 12);
  await db.user.update({
    where: { id: session.user.id },
    data: { password: hashed },
  });

  return { success: "Password changed successfully." };
}

// ─── Update Shipping Details ──────────────────────────────────────────────────

export async function updateShippingAction(
  _prev: ActionResult,
  formData: FormData
): Promise<ActionResult> {
  const session = await auth();
  if (!session?.user?.id) return { error: "Not authenticated." };

  const shippingAddress = String(formData.get("shippingAddress") ?? "").trim();
  const shippingCity = String(formData.get("shippingCity") ?? "").trim();
  const shippingState = String(formData.get("shippingState") ?? "").trim();
  const shippingZip = String(formData.get("shippingZip") ?? "").trim();
  const shippingCountry = String(formData.get("shippingCountry") ?? "").trim() || "Malaysia";

  await db.user.update({
    where: { id: session.user.id },
    data: {
      shippingAddress: shippingAddress || null,
      shippingCity: shippingCity || null,
      shippingState: shippingState || null,
      shippingZip: shippingZip || null,
      shippingCountry,
    },
  });

  return { success: "Shipping address updated successfully." };
}
