import { NextResponse } from "next/server";
import bcrypt from "bcryptjs";
import { prisma } from "@/lib/prisma";
import {
  SESSION_COOKIE,
  SESSION_MAX_AGE_SECONDS,
  signSession,
  homeForRole,
  isMemberRole,
} from "@/lib/auth";

/** Audit-trail writer — every sign-in attempt (success or failure) lands in
 *  login_logs for the HR → Login Audit view. Never throws into the login
 *  flow itself. */
async function logLogin(entry: {
  institutionId: number | null;
  userId: number | null;
  name: string;
  role: string | null;
  identifier: string;
  success: boolean;
  reason?: string;
  req: Request;
}) {
  try {
    const fwd = entry.req.headers.get("x-forwarded-for");
    await prisma.loginLog.create({
      data: {
        institutionId: entry.institutionId,
        userId: entry.userId,
        name: entry.name.slice(0, 120),
        role: entry.role,
        identifier: entry.identifier.slice(0, 160),
        success: entry.success,
        reason: entry.reason ?? null,
        ip: (fwd ? fwd.split(",")[0].trim() : null) ?? "local",
        userAgent: entry.req.headers.get("user-agent")?.slice(0, 500) ?? null,
      },
    });
  } catch {
    /* audit failures must never block a login */
  }
}

export async function POST(req: Request) {
  try {
    const body = await req.json();
    const email = String(body.email ?? "").trim().toLowerCase();
    const password = String(body.password ?? "");
    // Members (student/teacher/parent/staff and the other staff-side roles)
    // sign in with institution code + username; the code scopes the username
    // to one registered institution.
    const institutionCode = String(body.institutionCode ?? "").trim().toUpperCase();
    const username = String(body.username ?? "").trim();
    // member branch: the resolved institution (for auditing unknown usernames)
    let institutionIdHint: number | null = null;

    if (!password) {
      return NextResponse.json({ error: "Password is required" }, { status: 400 });
    }

    let user;

    if (institutionCode) {
      if (!username) {
        return NextResponse.json({ error: "USERNAME_REQUIRED" }, { status: 400 });
      }
      const institution = await prisma.institution.findUnique({
        where: { code: institutionCode },
        select: { id: true, status: true, name: true },
      });
      if (!institution) {
        return NextResponse.json({ error: "INVALID_CODE" }, { status: 404 });
      }
      if (institution.status !== "ACTIVE") {
        return NextResponse.json({ error: "INSTITUTION_INACTIVE" }, { status: 403 });
      }
      institutionIdHint = institution.id;
      user = await prisma.user.findFirst({
        where: { institutionId: institution.id, username },
        include: {
          institution: { select: { id: true, status: true, name: true } },
          studentProfile: { select: { status: true } },
          parentOfStudent: { select: { status: true } },
        },
      });
    } else {
      if (!email) {
        return NextResponse.json({ error: "Email and password are required" }, { status: 400 });
      }
      user = await prisma.user.findUnique({
        where: { email },
        include: {
          institution: { select: { id: true, status: true, name: true } },
          studentProfile: { select: { status: true } },
          parentOfStudent: { select: { status: true } },
        },
      });
    }

    if (!user || !(await bcrypt.compare(password, user.passwordHash))) {
      await logLogin({
        institutionId: user?.institutionId ?? institutionIdHint ?? null,
        userId: user?.id ?? null,
        name: user?.name ?? username ?? email,
        role: user?.role ?? null,
        identifier: institutionCode ? `${institutionCode} · ${username}` : email,
        success: false,
        reason: "INVALID_CREDENTIALS",
        req,
      });
      return NextResponse.json({ error: "Invalid credentials" }, { status: 401 });
    }

    // Disabled member accounts and deactivated students (or their parents)
    // must not keep portal access
    if (user.status === "INACTIVE") {
      await logLogin({
        institutionId: user.institutionId,
        userId: user.id,
        name: user.name,
        role: user.role,
        identifier: institutionCode ? `${institutionCode} · ${username}` : email,
        success: false,
        reason: "ACCOUNT_DISABLED",
        req,
      });
      return NextResponse.json({ error: "ACCOUNT_DISABLED" }, { status: 403 });
    }
    if (isMemberRole(user.role)) {
      const linked = user.studentProfile ?? user.parentOfStudent;
      if (linked?.status === "INACTIVE") {
        await logLogin({
          institutionId: user.institutionId,
          userId: user.id,
          name: user.name,
          role: user.role,
          identifier: institutionCode ? `${institutionCode} · ${username}` : email,
          success: false,
          reason: "STUDENT_INACTIVE",
          req,
        });
        return NextResponse.json({ error: "STUDENT_INACTIVE" }, { status: 403 });
      }
    }

    await prisma.user.update({
      where: { id: user.id },
      data: { lastLoginAt: new Date() },
      select: { id: true },
    });

    // Demo environments granted from the landing page stay usable only for
    // the validity window the central admin set (default 10 days) — once it
    // is over nobody of that demo institution can sign in any more.
    let demoExpiresAt: number | undefined;
    if (user.institutionId) {
      const demoGrant = await prisma.demoRequest.findFirst({
        where: { demoInstitutionId: user.institutionId, demoExpiresAt: { not: null } },
        select: { demoExpiresAt: true },
      });
      if (demoGrant?.demoExpiresAt) {
        if (demoGrant.demoExpiresAt.getTime() <= Date.now()) {
          await logLogin({
            institutionId: user.institutionId,
            userId: user.id,
            name: user.name,
            role: user.role,
            identifier: institutionCode ? `${institutionCode} · ${username}` : email,
            success: false,
            reason: "DEMO_EXPIRED",
            req,
          });
          return NextResponse.json({ error: "DEMO_EXPIRED" }, { status: 403 });
        }
        demoExpiresAt = Math.floor(demoGrant.demoExpiresAt.getTime() / 1000);
      }
    }

    await logLogin({
      institutionId: user.institutionId,
      userId: user.id,
      name: user.name,
      role: user.role,
      identifier: institutionCode ? `${institutionCode} · ${username}` : email,
      success: true,
      req,
    });

    const token = await signSession({
      userId: user.id,
      role: user.role,
      name: user.name,
      email: user.email,
      username: user.username,
      institutionId: user.institutionId,
      ...(demoExpiresAt ? { demoExpiresAt } : {}),
    });

    // Only mark the cookie Secure on real HTTPS (behind a proxy that sets
    // x-forwarded-proto). `NODE_ENV=production` alone is not enough — the app
    // is often served over plain HTTP (node app.js), where browsers reject
    // Secure cookies and the session is lost right after login.
    const proto =
      req.headers.get("x-forwarded-proto")?.split(",")[0].trim() ??
      new URL(req.url).protocol.replace(":", "");

    const res = NextResponse.json({
      user: {
        id: user.id,
        name: user.name,
        email: user.email,
        username: user.username,
        role: user.role,
        institution: user.institution,
      },
      redirect: homeForRole(user.role),
    });

    res.cookies.set(SESSION_COOKIE, token, {
      httpOnly: true,
      sameSite: "lax",
      secure: proto === "https",
      maxAge: SESSION_MAX_AGE_SECONDS, // login state is kept at most 3 hours
      path: "/",
    });

    return res;
  } catch {
    return NextResponse.json({ error: "Login failed" }, { status: 500 });
  }
}
