import fetchUser from "@/services/users/fetch";
import invalidateToken from "@/services/users/invalidateToken";
import { randomBytes, randomUUID } from "crypto";
import { AuthOptions, SessionStrategy } from "next-auth";
import { JWT } from "next-auth/jwt";
import CredentialsProvider from "next-auth/providers/credentials";
import { Credentials, TSignIn } from "./types";
import { validProps } from "./validProps";

export const MAX_AGE = 24 * 60 * 60;

const AuthOption: AuthOptions = {
  pages: {
    signIn: "/auth/login",
  },
  session: {
    strategy: "jwt" as SessionStrategy,
    maxAge: MAX_AGE,
    updateAge: MAX_AGE * 30,
    generateSessionToken: () => {
      return randomUUID?.() ?? randomBytes(32).toString("hex");
    },
  },
  secret: process.env.NEXTAUTH_SECRET,
  providers: [
    CredentialsProvider({
      credentials: {
        user: { label: "Username", type: "text" },
        password: { label: "Password", type: "password" },
      },
      authorize: async (credentials) => {
        const { user, password } = credentials as Credentials;

        const isUser = await fetchUser({ user, password, isAuth: false });

        if (!isUser) {
          return null;
        }

        return isUser;
      },
    }),
  ],
  callbacks: {
    async signIn(params): Promise<boolean | string> {
      const { user, account } = params as TSignIn;

      const providers: { [key: string]: any } = {
        credentials: () => true,
        "not-listed": () => false,
      };

      return providers[account?.provider || "not-listed"]();
    },
    async jwt(params): Promise<JWT> {
      const { token, user, trigger, session } = params as TSignIn;

      if (token && trigger === "update" && session) {
        Object.keys(session)
          .filter((prop) => validProps.includes(prop))
          .forEach((prop) => {
            token[prop] = (session as any)[prop];
          });
      }

      if (token && !token.id) {
        token.id = user?.id;
        token.tId = user?.tId;
        token.email = user?.email;
        token.name = user?.name;
        token.permissions = user?.permissions;
      }

      return token as JWT;
    },
    async session(params): Promise<any> {
      const { session, token } = params as unknown as TSignIn;

      if (session && session.user && token) {
        session.user = {
          ...session.user,
          ...(token as any),
        };
      }

      return await Promise.resolve(session);
    },
  },
  events: {
    async signOut(message) {
      const { token } = message;

      if (token) {
        await invalidateToken(token)
      }
    },
  },
};

export { AuthOption };

