import { NextResponse } from "next/server";

import { sendEmailVerificationEmail } from "@/features/auth/lib/auth-emails";
import {
  buildEmailVerificationUrl,
  issueEmailVerificationToken
} from "@/features/auth/lib/email-verification";
import { updateUserSchema } from "@/features/users/schemas/user.schema";
import { serializeUser } from "@/features/users/lib/serialize-user";
import { createAuditTrailSafe } from "@/lib/audit-trail";
import { requireApiAccess } from "@/lib/authorization";
import { prisma } from "@/lib/prisma";

type RouteContext = { params: Promise<{ id: string }> };

function parseBigInt(value: string) {
  try {
    return BigInt(value);
  } catch {
    return null;
  }
}

export async function PUT(request: Request, context: RouteContext) {
  const auth = requireApiAccess(request);
  if (!auth.ok) return auth.response;

  const id = parseBigInt((await context.params).id);
  if (id === null) {
    return NextResponse.json({ message: "Invalid id" }, { status: 400 });
  }

  try {
    const parsed = updateUserSchema.safeParse(await request.json());
    if (!parsed.success) {
      return NextResponse.json(
        {
          message: "Validasi gagal",
          errors: parsed.error.flatten().fieldErrors
        },
        { status: 422 }
      );
    }

    const currentUser = await prisma.user.findUnique({
      where: { id },
      include: { role: true }
    });

    if (!currentUser) {
      return NextResponse.json({ message: "User tidak ditemukan" }, { status: 404 });
    }

    const email = parsed.data.email.toLowerCase();
    const username = parsed.data.username.toLowerCase();

    const [role, existingEmail, existingUsername] = await Promise.all([
      prisma.role.findUnique({ where: { code: parsed.data.role_code } }),
      prisma.user.findFirst({
        where: {
          email,
          id: { not: id }
        }
      }),
      prisma.user.findFirst({
        where: {
          username,
          id: { not: id }
        }
      })
    ]);

    if (!role) {
      return NextResponse.json({ message: "Role tidak ditemukan" }, { status: 404 });
    }
    if (existingEmail) {
      return NextResponse.json({ message: "Email sudah dipakai" }, { status: 409 });
    }
    if (existingUsername) {
      return NextResponse.json({ message: "Username sudah dipakai" }, { status: 409 });
    }

    const emailChanged = currentUser.email !== email;

    const updatedUser = await prisma.user.update({
      where: { id },
      data: {
        roleId: role.id,
        name: parsed.data.name,
        email,
        username,
        phone: parsed.data.phone || null,
        status: parsed.data.status,
        emailVerifiedAt: emailChanged ? null : currentUser.emailVerifiedAt
      },
      include: {
        role: true
      }
    });

    if (emailChanged) {
      await prisma.emailVerificationToken.deleteMany({
        where: { userId: id }
      });

      const { plainToken } = await issueEmailVerificationToken(updatedUser.id);
      await sendEmailVerificationEmail({
        to: updatedUser.email!,
        name: updatedUser.name,
        verifyUrl: buildEmailVerificationUrl(plainToken)
      });
    }

    await createAuditTrailSafe({
      userId: auth.user.id,
      action: "USER_UPDATED",
      entityType: "USER",
      entityId: updatedUser.id,
      method: request.method,
      pathname: new URL(request.url).pathname,
      statusCode: 200,
      summary: emailChanged
        ? `User ${updatedUser.email ?? updatedUser.username ?? updatedUser.name} diperbarui dan verifikasi email direset`
        : `User ${updatedUser.email ?? updatedUser.username ?? updatedUser.name} diperbarui`,
      metadata: {
        before: {
          name: currentUser.name,
          email: currentUser.email,
          username: currentUser.username,
          phone: currentUser.phone,
          status: currentUser.status,
          role_code: currentUser.role.code,
          email_verified_at: currentUser.emailVerifiedAt?.toISOString() ?? null
        },
        after: {
          name: updatedUser.name,
          email: updatedUser.email,
          username: updatedUser.username,
          phone: updatedUser.phone,
          status: updatedUser.status,
          role_code: updatedUser.role.code,
          email_verified_at: updatedUser.emailVerifiedAt?.toISOString() ?? null
        }
      }
    });

    return NextResponse.json({
      data: serializeUser(updatedUser),
      message: emailChanged
        ? "User berhasil diperbarui. Email berubah, verifikasi ulang sudah dikirim."
        : "User berhasil diperbarui."
    });
  } catch (error) {
    return NextResponse.json(
      {
        message: error instanceof Error ? error.message : "Gagal memperbarui user"
      },
      { status: 500 }
    );
  }
}

export async function DELETE(request: Request, context: RouteContext) {
  const auth = requireApiAccess(request);
  if (!auth.ok) return auth.response;

  const id = parseBigInt((await context.params).id);
  if (id === null) {
    return NextResponse.json({ message: "Invalid id" }, { status: 400 });
  }

  if (id.toString() === auth.user.id) {
    return NextResponse.json({ message: "Anda tidak bisa menghapus akun Anda sendiri." }, { status: 422 });
  }

  const user = await prisma.user.findUnique({ where: { id } });
  if (!user) {
    return NextResponse.json({ message: "User tidak ditemukan" }, { status: 404 });
  }

  try {
    await prisma.user.delete({ where: { id } });
    await createAuditTrailSafe({
      userId: auth.user.id,
      action: "USER_DELETED",
      entityType: "USER",
      entityId: id,
      method: request.method,
      pathname: new URL(request.url).pathname,
      statusCode: 200,
      summary: `User ${user.email ?? user.username ?? user.name} dihapus`
    });
    return NextResponse.json({ message: "User berhasil dihapus" });
  } catch {
    return NextResponse.json(
      { message: "User tidak bisa dihapus karena sudah terhubung ke data transaksi." },
      { status: 409 }
    );
  }
}
