"use server";

import { createHash } from "node:crypto";
import { redirect } from "next/navigation";
import { and, eq, isNull, gt } from "drizzle-orm";
import { z } from "zod";
import { db } from "@/db";
import { users, passwordResetTokens, auditLogs } from "@/db/schema";
import { hashPassword } from "@/lib/password";

const resetSchema = z
  .object({
    token: z.string().min(1),
    password: z.string().min(8, "Mật khẩu mới phải có ít nhất 8 ký tự."),
    confirm: z.string(),
  })
  .refine((data) => data.password === data.confirm, {
    message: "Mật khẩu nhập lại không khớp.",
    path: ["confirm"],
  });

export type ResetPasswordState = { error?: string };

export async function resetPasswordAction(
  _prev: ResetPasswordState,
  formData: FormData,
): Promise<ResetPasswordState> {
  const parsed = resetSchema.safeParse({
    token: formData.get("token"),
    password: formData.get("password"),
    confirm: formData.get("confirm"),
  });
  if (!parsed.success) return { error: parsed.error.issues[0].message };

  const tokenHash = createHash("sha256").update(parsed.data.token).digest("hex");

  const [row] = await db
    .select({ id: passwordResetTokens.id, userId: passwordResetTokens.userId, tenantId: passwordResetTokens.tenantId })
    .from(passwordResetTokens)
    .where(
      and(
        eq(passwordResetTokens.tokenHash, tokenHash),
        isNull(passwordResetTokens.usedAt),
        gt(passwordResetTokens.expiresAt, new Date()),
      ),
    )
    .limit(1);

  if (!row) {
    return { error: "Đường dẫn đặt lại mật khẩu không hợp lệ hoặc đã hết hạn. Hãy yêu cầu đường dẫn mới." };
  }

  // Tài khoản đã bị khoá sau khi xin đường dẫn thì không đặt lại được.
  const [owner] = await db
    .select({ isActive: users.isActive })
    .from(users)
    .where(and(eq(users.id, row.userId), eq(users.tenantId, row.tenantId)))
    .limit(1);
  if (!owner?.isActive) return { error: "Tài khoản đã bị khoá. Liên hệ quản trị viên." };

  const passwordHash = await hashPassword(parsed.data.password);

  await db
    .update(users)
    // Xoá luôn trạng thái tạm khoá do nhập sai, và đăng xuất mọi phiên cũ.
    .set({ passwordHash, passwordChangedAt: new Date(), failedLoginCount: 0, lockedUntil: null })
    .where(and(eq(users.id, row.userId), eq(users.tenantId, row.tenantId)));
  // Mọi đường dẫn đặt lại còn lại của tài khoản này cũng hết hiệu lực.
  await db
    .update(passwordResetTokens)
    .set({ usedAt: new Date() })
    .where(and(eq(passwordResetTokens.userId, row.userId), isNull(passwordResetTokens.usedAt)));

  await db.insert(auditLogs).values({
    tenantId: row.tenantId,
    userId: row.userId,
    action: "UPDATE",
    entityType: "password_reset",
    entityId: row.userId,
  });

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