import bcrypt from "bcryptjs";
import User from "@/models/user";
import { getDb } from "@/lib/db";
import { createSession } from "@/lib/auth/session";
import {
	withErrorHandling,
	json,
	badRequest,
	unauthorized,
} from "@/lib/api/errors";

/**
 * Next.js Route Handler caching configuration (RHL-006):
 *
 * We force this route to execute dynamically on every request.
 *
 * Reasons:
 * - NAS contents can change at any time (new scans).
 * - Auth/RBAC-protected responses must not be cached/shared across users.
 * - We rely on a small storage-layer TTL micro-cache instead of Next route caching.
 */
export const dynamic = "force-dynamic";

/**
 * POST /api/auth/login
 *
 * Body (JSON):
 * {
 *   "username": "example.user",
 *   "password": "plain-text-password"
 * }
 *
 * Error contract (standardized):
 * {
 *   "error": { "message": "...", "code": "...", "details"?: {...} }
 * }
 */
export const POST = withErrorHandling(
	async function POST(request) {
		// --- 1) Parse body ------------------------------------------------------
		// request.json() can throw if the JSON is invalid (e.g. broken body).
		let body;
		try {
			body = await request.json();
		} catch {
			throw badRequest("VALIDATION_INVALID_JSON", "Invalid request body");
		}

		// We only accept objects as JSON body for this endpoint.
		if (!body || typeof body !== "object") {
			throw badRequest("VALIDATION_INVALID_BODY", "Invalid request body");
		}

		// --- 2) Validate credentials input -------------------------------------
		const { username, password } = body;

		// Keep validation strict and predictable:
		// - Must be strings
		// - Must not be empty/whitespace
		if (
			typeof username !== "string" ||
			typeof password !== "string" ||
			!username.trim() ||
			!password.trim()
		) {
			throw badRequest(
				"VALIDATION_MISSING_FIELD",
				"Missing username or password",
				{
					fields: ["username", "password"],
				},
			);
		}

		// Normalize usernames to avoid case/whitespace issues.
		const normalizedUsername = username.trim().toLowerCase();

		// --- 3) Load user from DB ----------------------------------------------
		// Ensure DB (Mongoose) connection is established before using models.
		await getDb();

		const user = await User.findOne({ username: normalizedUsername }).exec();

		// Do not leak whether a username exists; always return "Invalid credentials".
		if (!user) {
			throw unauthorized("AUTH_INVALID_CREDENTIALS", "Invalid credentials");
		}

		// Defensive: never let missing/invalid passwordHash crash the endpoint.
		// Treat it like invalid credentials.
		if (typeof user.passwordHash !== "string" || !user.passwordHash) {
			throw unauthorized("AUTH_INVALID_CREDENTIALS", "Invalid credentials");
		}

		// --- 4) Verify password -------------------------------------------------
		const passwordMatches = await bcrypt.compare(password, user.passwordHash);

		if (!passwordMatches) {
			throw unauthorized("AUTH_INVALID_CREDENTIALS", "Invalid credentials");
		}

		// --- 5) Create session cookie ------------------------------------------
		await createSession({
			userId: user._id.toString(),
			role: user.role,
			branchId: user.branchId ?? null,
			email: user.email ?? null,
			mustChangePassword: Boolean(user.mustChangePassword),
		});

		// Happy path response stays unchanged:
		return json({ ok: true }, 200);
	},
	{ logPrefix: "[api/auth/login]" },
);
