import type { NextAuthOptions } from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";
import GoogleProvider from "next-auth/providers/google";
import type { UserRole } from "@/types";
import { z } from "zod";
import { initDb } from "@/lib/db";
import {
  findUserByEmail,
  verifyPassword,
  toSessionUser,
} from "@/lib/auth/credentials";

const credentialsSchema = z.object({
  email: z.string().email(),
  password: z.string().min(8),
});

const SESSION_MAX_AGE_SEC = 60 * 60 * 24 * 7; // 7 days
const JWT_REVALIDATE_MS = 5 * 60 * 1000; // re-check DB every 5 min

if (
  process.env.NODE_ENV === "production" &&
  (!process.env.NEXTAUTH_SECRET ||
    process.env.NEXTAUTH_SECRET === "generate-a-long-random-secret-here")
) {
  console.error(
    "[auth] NEXTAUTH_SECRET is missing or insecure — set a long random secret in production."
  );
}

export const authOptions: NextAuthOptions = {
  session: {
    strategy: "jwt",
    maxAge: SESSION_MAX_AGE_SEC,
  },
  jwt: {
    maxAge: SESSION_MAX_AGE_SEC,
  },
  pages: {
    signIn: "/login",
    error: "/login",
  },
  providers: [
    CredentialsProvider({
      name: "credentials",
      credentials: {
        email: { label: "Email", type: "email" },
        password: { label: "Password", type: "password" },
      },
      async authorize(credentials) {
        const parsed = credentialsSchema.safeParse(credentials);
        if (!parsed.success) return null;

        const user = await findUserByEmail(parsed.data.email);
        if (!user?.passwordHash) return null;

        const valid = await verifyPassword(
          parsed.data.password,
          user.passwordHash
        );
        if (!valid) return null;

        await user.update({ lastLoginAt: new Date() });
        return toSessionUser(user);
      },
    }),
    ...(process.env.GOOGLE_CLIENT_ID && process.env.GOOGLE_CLIENT_SECRET
      ? [
          GoogleProvider({
            clientId: process.env.GOOGLE_CLIENT_ID,
            clientSecret: process.env.GOOGLE_CLIENT_SECRET,
            allowDangerousEmailAccountLinking: false,
          }),
        ]
      : []),
  ],
  callbacks: {
    async signIn({ user, account }) {
      if (account?.provider !== "google") return true;

      const { User: UserModel } = initDb();
      const email = user.email?.toLowerCase();
      if (!email) return false;

      let dbUser = await UserModel.findOne({ where: { email } });
      if (!dbUser) {
        const { getPlatformSettings } = await import(
          "@/lib/queries/system-settings-queries"
        );
        const platform = await getPlatformSettings();
        if (!platform.signupsEnabled) return false;

        dbUser = await UserModel.create({
          name: user.name || email.split("@")[0],
          email,
          role: "client",
          passwordHash: null,
          avatarUrl: user.image ?? null,
          lastLoginAt: new Date(),
        });
      } else {
        if (!dbUser.isActive) return false;
        await dbUser.update({ lastLoginAt: new Date() });
      }

      return dbUser.isActive;
    },
    async jwt({ token, user, trigger }) {
      const now = Date.now();
      const lastChecked = typeof token.lastChecked === "number" ? token.lastChecked : 0;
      const shouldRevalidate =
        Boolean(token.id) &&
        (trigger === "update" ||
          !lastChecked ||
          now - lastChecked > JWT_REVALIDATE_MS);

      if (shouldRevalidate && token.id) {
        try {
          const { User: UserModel } = initDb();
          const dbUser = await UserModel.findByPk(token.id as string);
          if (!dbUser?.isActive) {
            return { error: "SessionInvalid" };
          }
          token.role = dbUser.role;
          token.workspaceId = dbUser.workspaceId ?? null;
          token.name = dbUser.name;
          token.email = dbUser.email;
          token.picture = dbUser.avatarUrl;
          token.lastChecked = now;
          delete token.error;
          return token;
        } catch {
          // Keep existing token on transient DB errors; page guards re-check.
          return token;
        }
      }

      if (user?.email) {
        const { User: UserModel } = initDb();
        const dbUser = await UserModel.findOne({
          where: { email: user.email.toLowerCase(), isActive: true },
        });
        if (dbUser) {
          token.id = dbUser.id;
          token.role = dbUser.role;
          token.workspaceId = dbUser.workspaceId ?? null;
          token.name = dbUser.name;
          token.email = dbUser.email;
          token.picture = dbUser.avatarUrl ?? user.image ?? null;
          token.lastChecked = now;
          delete token.error;
          return token;
        }
        return { error: "SessionInvalid" };
      }

      if (user?.id) {
        token.id = user.id;
        token.role = user.role;
        token.workspaceId = user.workspaceId ?? null;
        token.name = user.name;
        token.email = user.email;
        token.picture = user.image ?? null;
        token.lastChecked = now;
        delete token.error;
      }

      return token;
    },
    async session({ session, token }) {
      if (token.error || !token.id) {
        return {
          ...session,
          user: {
            ...session.user,
            id: "",
            name: null,
            email: null,
            image: null,
            role: "client",
            workspaceId: null,
          },
        };
      }
      if (session.user) {
        session.user.id = token.id as string;
        session.user.role = token.role as UserRole;
        session.user.workspaceId = (token.workspaceId as string | null) ?? null;
        session.user.name = token.name as string;
        session.user.email = token.email as string;
        session.user.image = (token.picture as string | null) ?? null;
      }
      return session;
    },
  },
  secret: process.env.NEXTAUTH_SECRET,
};
