import { betterAuth } from "better-auth";
import { drizzleAdapter } from "@better-auth/drizzle-adapter";
import { jwt, magicLink, organization, twoFactor } from "better-auth/plugins";
import { env } from "@/env";
import { db } from "@/lib/db";
import * as schema from "@/lib/db/auth-schema";
import { sendEmail } from "@/lib/email";

export const auth = betterAuth({
  appName: "seoinsight",
  baseURL: env.BETTER_AUTH_URL,
  secret: env.BETTER_AUTH_SECRET,
  database: drizzleAdapter(db, { provider: "pg", schema }),
  emailAndPassword: { enabled: true },
  databaseHooks: {
    session: {
      create: {
        // Better Auth recrée la session en passant l'ancienne en override (confirmation TOTP,
        // désactivation 2FA, changement de mot de passe, vérification d'email) : ne rien
        // toucher si une organisation active est déjà portée par la session.
        before: async (session) => {
          if (session.activeOrganizationId) return;
          const first = await db.query.member.findFirst({
            where: (fields, { eq }) => eq(fields.userId, session.userId),
            orderBy: (fields, { asc }) => asc(fields.createdAt),
            columns: { organizationId: true },
          });
          return { data: { activeOrganizationId: first?.organizationId ?? null } };
        },
      },
    },
  },
  plugins: [
    organization(),
    twoFactor(),
    magicLink({
      sendMagicLink: async ({ email, url }) => {
        await sendEmail({
          to: email,
          subject: "Votre lien de connexion seoinsight",
          html: `<p>Cliquez pour vous connecter : <a href="${url}">${url}</a></p>`,
        });
      },
    }),
    jwt({
      // Ne désactive **que** le header `set-auth-jwt` que Better Auth ajouterait sur chaque
      // `/get-session` : un jeton émis à chaque rafraîchissement de page, pour tout le monde,
      // qu'on l'utilise ou non. L'endpoint `GET /api/auth/token` reste ouvert, et il est
      // **délibérément appelé depuis le navigateur** par l'upload direct (décision n°8,
      // `components/jobs/upload-dropzone.tsx`) : c'est le seul jeton qui atteint le client,
      // demandé explicitement, juste avant l'envoi du fichier. Ne pas « durcir » en fermant
      // cet endpoint — l'upload direct cesserait de fonctionner.
      disableSettingJwtHeader: true,
      jwt: {
        expirationTime: "15m",
        // `session.activeOrganizationId` n'est pas une preuve d'appartenance : le plugin
        // organization ne nettoie ce champ que dans la session de l'acteur, jamais dans
        // celles d'un membre retiré par un admin. On revérifie donc l'appartenance à
        // chaque émission de jeton.
        definePayload: async ({ user, session }) => {
          const activeOrganizationId = session.activeOrganizationId as string | null | undefined;
          const membership = activeOrganizationId
            ? await db.query.member.findFirst({
                where: (fields, { and, eq }) =>
                  and(eq(fields.userId, user.id), eq(fields.organizationId, activeOrganizationId)),
                columns: { id: true },
              })
            : undefined;
          return {
            email: user.email,
            org_id: membership ? activeOrganizationId : null,
          };
        },
      },
    }),
  ],
});
