import {PrismaAdapter} from "@auth/prisma-adapter";
import bcrypt from "bcrypt";
import type {NextAuthConfig} from "next-auth";
import Credentials from "next-auth/providers/credentials";
import {logAudit} from "@/lib/audit/log";
import {getSessionClaims} from "@/lib/auth/memberships";
import {prisma} from "@/lib/db/prisma";
import {signInSchema} from "@/lib/validations/auth";

export const authConfig: NextAuthConfig = {
  adapter: PrismaAdapter(prisma),
  session: {
    strategy: "jwt"
  },
  pages: {
    signIn: "/en/auth/sign-in"
  },
  providers: [
    Credentials({
      name: "credentials",
      credentials: {
        email: {label: "Email", type: "email"},
        password: {label: "Password", type: "password"}
      },
      async authorize(rawCredentials) {
        const credentials = signInSchema.safeParse(rawCredentials);

        if (!credentials.success) {
          return null;
        }

        const user = await prisma.user.findUnique({
          where: {
            email: credentials.data.email.toLowerCase()
          }
        });

        if (!user?.passwordHash || user.status !== "ACTIVE") {
          return null;
        }

        const isValid = await bcrypt.compare(credentials.data.password, user.passwordHash);

        if (!isValid) {
          return null;
        }

        const claims = await getSessionClaims(user.id);

        return {
          id: user.id,
          email: user.email,
          name: user.name ?? ([user.firstName, user.lastName].filter(Boolean).join(" ") || null),
          preferredLanguage: claims.preferredLanguage,
          platformRole: claims.platformRole,
          memberships: claims.memberships,
          activeTenantId: claims.activeTenantId
        };
      }
    })
  ],
  callbacks: {
    async jwt({token, user, trigger, session}) {
      const currentUserId = typeof user?.id === "string" ? user.id : typeof token.userId === "string" ? token.userId : null;

      if (currentUserId) {
        const claims = await getSessionClaims(currentUserId);
        token.userId = claims.userId;
        token.platformRole = claims.platformRole;
        token.memberships = claims.memberships;
        token.activeTenantId = claims.activeTenantId;
        token.preferredLanguage = claims.preferredLanguage;
      }

      if (trigger === "update" && session?.activeTenantId) {
        token.activeTenantId = session.activeTenantId;
      }

      return token;
    },
    async session({session, token}) {
      if (!session.user || typeof token.userId !== "string" || typeof token.preferredLanguage !== "string") {
        return session;
      }

      session.user.id = token.userId;
      session.user.platformRole = token.platformRole ?? null;
      session.user.memberships = token.memberships ?? [];
      session.user.activeTenantId = token.activeTenantId ?? null;
      session.user.preferredLanguage = token.preferredLanguage as "ar" | "en";

      return session;
    },
    async signIn({user}) {
      if (!user.id) {
        return false;
      }

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

      const claims = await getSessionClaims(user.id);

      await logAudit({
        action: "LOGIN",
        entityType: "User",
        entityId: user.id,
        tenantId: claims.activeTenantId,
        userId: user.id,
        newValues: {
          preferredLanguage: claims.preferredLanguage,
          platformRole: claims.platformRole ?? "NONE"
        }
      });

      return true;
    }
  }
};