import { NextRequest, NextResponse } from "next/server";
import { db, hashPassword, verifyPassword, hashPin } from "@/lib/admin/db";
import { requireAuth, getClientMetadata } from "@/lib/admin/auth";

export async function POST(req: NextRequest) {
  try {
    const { user, session } = await requireAuth(req);
    const { ip, location } = getClientMetadata(req);

    const body = await req.json();
    const currentPassword = typeof body.currentPassword === "string" ? body.currentPassword : "";
    const newPassword = typeof body.newPassword === "string" ? body.newPassword : "";
    const pin = typeof body.pin === "string" ? body.pin.trim() : "";
    const confirmPin = typeof body.confirmPin === "string" ? body.confirmPin.trim() : "";

    if (!currentPassword || !newPassword) {
      return NextResponse.json(
        { error: "Both current password and new password are required." },
        { status: 400 }
      );
    }

    // Verify current password
    const valid = verifyPassword(currentPassword, user.passwordHash, user.passwordSalt);
    if (!valid) {
      return NextResponse.json(
        { error: "Current password does not match our records." },
        { status: 400 }
      );
    }

    // Validate new password quality
    if (newPassword.length < 8) {
      return NextResponse.json(
        { error: "New password must be at least 8 characters long." },
        { status: 400 }
      );
    }

    if (currentPassword === newPassword) {
      return NextResponse.json(
        { error: "New password must be different from your existing password." },
        { status: 400 }
      );
    }

    // If setting PIN during initial setup or if PIN was provided
    let pinUpdates: Record<string, any> = {};
    if (pin || !user.pinHash) {
      if (!/^\d{4}$/.test(pin)) {
        return NextResponse.json(
          { error: "Screen lock PIN must consist of exactly 4 numeric digits (0-9)." },
          { status: 400 }
        );
      }
      if (pin !== confirmPin) {
        return NextResponse.json(
          { error: "Screen lock PIN and confirmation PIN do not match." },
          { status: 400 }
        );
      }
      const weakPins = ["0000", "1111", "2222", "3333", "4444", "5555", "6666", "7777", "8888", "9999", "1234", "4321"];
      if (weakPins.includes(pin)) {
        return NextResponse.json(
          { error: "Please choose a more secure PIN (avoid sequential or repeated digits like 1234 or 0000)." },
          { status: 400 }
        );
      }
      const { hash: pHash, salt: pSalt } = hashPin(pin);
      pinUpdates = { pinHash: pHash, pinSalt: pSalt, pinSetupRequired: false };
    }

    // Hash and update
    const { hash, salt } = hashPassword(newPassword);
    await db.updateUser(user.id, {
      passwordHash: hash,
      passwordSalt: salt,
      passwordChangeRequired: false,
      ...pinUpdates,
    });

    // Revoke all OTHER sessions on password change for security
    const otherSessionsRevoked = await db.revokeOtherSessions(
      user.id,
      session.tokenHash,
      user.email,
      "PASSWORD_CHANGE"
    );

    // Security audit log (NEVER include passwords or PINs!)
    await db.logSecurityEvent({
      actorId: user.id,
      actorName: user.name,
      actorEmail: user.email,
      actorLevel: user.level,
      targetUserId: user.id,
      targetUserEmail: user.email,
      targetUserName: user.name,
      action: "PASSWORD_CHANGE",
      details: {
        note: "Password successfully changed by account holder.",
        forcedPasswordChangeResolved: user.passwordChangeRequired,
        otherSessionsRevoked,
      },
      ipAddress: ip,
      location: location || session.location,
    });

    return NextResponse.json({
      ok: true,
      message: "Password updated successfully.",
    });
  } catch (error) {
    const status = (error as unknown as { status: number }).status || 500;
    return NextResponse.json(
      { error: (error as Error).message || "Failed to update password." },
      { status }
    );
  }
}
