import NextAuth, { type DefaultSession } from "next-auth";
import Google from "next-auth/providers/google";
import { DrizzleAdapter } from "@auth/drizzle-adapter";
import { eq } from "drizzle-orm";
import { db, users, accounts, sessions, verificationTokens, people } from "@/db";

type Role = "STAFF" | "EDITOR" | "ADMIN";

declare module "next-auth" {
  interface Session {
    user: DefaultSession["user"] & { id: string; role: Role; personSlug?: string | null };
  }
}

const allowedDomain = process.env.ALLOWED_GOOGLE_DOMAIN ?? "connellypartners.com";
const adminEmails = (process.env.ADMIN_EMAILS ?? "")
  .split(",")
  .map((e) => e.trim().toLowerCase())
  .filter(Boolean);

export const { handlers, auth, signIn, signOut } = NextAuth({
  adapter: DrizzleAdapter(db, { usersTable: users, accountsTable: accounts, sessionsTable: sessions, verificationTokensTable: verificationTokens }),
  session: { strategy: "database", maxAge: 60 * 60 * 24 * 14 },
  pages: { signIn: "/login", error: "/login" },
  trustHost: true,
  providers: [
    Google({
      authorization: {
        params: {
          // `hd` hints Google to show only Workspace accounts; we still verify the claim below.
          hd: allowedDomain,
          prompt: "select_account",
        },
      },
    }),
  ],
  callbacks: {
    /**
     * Gate: only verified Google Workspace accounts on our domain can sign in.
     * The `hd` claim is the authoritative check – an email suffix alone isn't enough.
     */
    async signIn({ account, profile }) {
      if (account?.provider !== "google") return false;
      const p = profile as { hd?: string; email?: string; email_verified?: boolean } | undefined;
      if (!p?.email_verified) return false;
      if (p.hd !== allowedDomain) return false;
      if (!p.email?.toLowerCase().endsWith(`@${allowedDomain}`)) return false;
      return true;
    },
    async session({ session, user }) {
      const row = await db.query.users.findFirst({ where: eq(users.id, user.id), with: { person: { columns: { slug: true } } } });
      session.user.id = user.id;
      session.user.role = row?.role ?? "STAFF";
      session.user.personSlug = row?.person?.slug ?? null;
      return session;
    },
  },
  events: {
    /** First sign-in: grant admin if listed, and link/create the Person profile by email. */
    async createUser({ user }) {
      if (!user.email || !user.id) return;
      const email = user.email.toLowerCase();
      const role: Role = adminEmails.includes(email) ? "ADMIN" : "STAFF";
      await db.update(users).set({ role }).where(eq(users.id, user.id));
      const person = await db.query.people.findFirst({ where: eq(people.email, email) });
      if (person && !person.userId) {
        await db.update(people).set({ userId: user.id, photoUrl: person.photoUrl ?? user.image ?? null }).where(eq(people.id, person.id));
      } else if (!person) {
        const [firstName, ...rest] = (user.name ?? email.split("@")[0]).split(" ");
        await db.insert(people).values({
          userId: user.id,
          email,
          firstName,
          lastName: rest.join(" "),
          slug: email.split("@")[0].replace(/[^a-z0-9]+/g, "-"),
          title: "New starter",
          department: "Unassigned",
          photoUrl: user.image ?? null,
        });
      }
    },
  },
});
