import NextAuth from "next-auth"
import { prisma } from "@/lib/prisma"
import { PrismaAdapter } from "@auth/prisma-adapter"
import Google from "next-auth/providers/google"
import Facebook from "next-auth/providers/facebook"
import Credentials from "next-auth/providers/credentials"
import { verifyCredentials } from "@/lib/auth-credentials"

type AuthProviderSettings = {
    google_id: string;
    google_secret: string;
    facebook_id: string;
    facebook_secret: string;
};

// Lazy loading of auth settings - only fetch when actually needed
let cachedSettings: AuthProviderSettings | null = null;
let settingsFetched = false;

async function getAuthSettings() {
    // Return cached settings if already fetched
    if (settingsFetched) {
        return cachedSettings;
    }

    try {
        // Fetch all auth-related system settings
        const settings = await prisma.systemSettings.findMany({
            where: {
                key: {
                    in: ['google_id', 'google_secret', 'facebook_id', 'facebook_secret']
                }
            }
        });

        const settingsMap = settings.reduce((acc, curr) => {
            acc[curr.key] = curr.value as string;
            return acc;
        }, {} as Record<string, string>);

        cachedSettings = {
            google_id: settingsMap.google_id || process.env.GOOGLE_CLIENT_ID || "",
            google_secret: settingsMap.google_secret || process.env.GOOGLE_CLIENT_SECRET || "",
            facebook_id: settingsMap.facebook_id || process.env.FACEBOOK_CLIENT_ID || "",
            facebook_secret: settingsMap.facebook_secret || process.env.FACEBOOK_CLIENT_SECRET || "",
        };
    } catch (error) {
        console.warn("[NextAuth] Failed to load auth settings from database, using env vars:", error);
        cachedSettings = {
            google_id: process.env.GOOGLE_CLIENT_ID || "",
            google_secret: process.env.GOOGLE_CLIENT_SECRET || "",
            facebook_id: process.env.FACEBOOK_CLIENT_ID || "",
            facebook_secret: process.env.FACEBOOK_CLIENT_SECRET || "",
        };
    }
    
    settingsFetched = true;
    return cachedSettings;
}

export const { handlers, signIn, signOut, auth } = NextAuth(async () => {
    const dynamicSettings = await getAuthSettings();

    return {
        adapter: PrismaAdapter(prisma),
        providers: [
            // Google OAuth - only register if credentials exist
            ...(dynamicSettings.google_id && dynamicSettings.google_id !== ""
                ? [
                    Google({
                        clientId: dynamicSettings.google_id,
                        clientSecret: dynamicSettings.google_secret,
                        allowDangerousEmailAccountLinking: true,
                    }),
                ]
                : []),
            // Facebook OAuth - only register if credentials exist
            ...(dynamicSettings.facebook_id && dynamicSettings.facebook_id !== ""
                ? [
                    Facebook({
                        clientId: dynamicSettings.facebook_id,
                        clientSecret: dynamicSettings.facebook_secret,
                        allowDangerousEmailAccountLinking: true,
                    }),
                ]
                : []),
            Credentials({
                name: "Credentials",
                credentials: {
                    email: { label: "Email", type: "email" },
                    password: { label: "Password", type: "password" }
                },
                async authorize(credentials) {
                    if (!credentials?.email || !credentials?.password) return null;

                    try {
                        const verified = await verifyCredentials(
                            credentials.email as string,
                            credentials.password as string,
                        );

                        if (!verified) return null;

                        try {
                            if (verified.tenantId) {
                                await prisma.activityLog.create({
                                    data: {
                                        tenantId: verified.tenantId,
                                        userId: verified.id,
                                        action: 'LOGIN',
                                        resource: 'user',
                                        resourceId: verified.id,
                                        details: { method: 'credentials', ip: 'server' },
                                    },
                                });
                            }
                        } catch { }

                        return verified;
                    } catch (error) {
                        console.error("Authentication flow error:", error);
                        return null;
                    }
                }
            })
        ],
        pages: {
            signIn: "/login",
            error: "/login",
        },
        callbacks: {
            async signIn({ user, account, profile }) {
                if (account?.provider !== 'credentials') {
                    // Check if user has a tenantId, if not, assign default or create one
                    if (user.id && !(user as any).tenantId) {
                        const existingUser = await prisma.user.findUnique({
                            where: { id: user.id },
                            select: { tenantId: true }
                        });

                        if (!existingUser?.tenantId) {
                            // Find the first available tenant or create a default one
                            let tenant = await prisma.tenant.findFirst();
                            if (!tenant) {
                                tenant = await prisma.tenant.create({
                                    data: {
                                        name: 'Default Tenant',
                                        plan: 'FREE'
                                    }
                                });
                            }
                            await prisma.user.update({
                                where: { id: user.id },
                                data: { tenantId: tenant.id }
                            });
                            (user as any).tenantId = tenant.id;
                        } else {
                            (user as any).tenantId = existingUser.tenantId;
                        }
                    }
                }
                return true;
            },
            async session({ session, token }: { session: any; token: any }) {
                if (session.user && token?.sub) {
                    session.user.id = token.sub;
                    (session.user as any).type = token.type;
                    (session.user as any).tenantId = token.tenantId;
                    (session.user as any).isOnboarded = token.isOnboarded;
                    (session.user as any).accessToken = token.accessToken;
                }
                
                // For OAuth users, if tenantId is missing in token, fetch it
                if (session.user && !(session.user as any).tenantId) {
                    const user = await prisma.user.findUnique({
                        where: { id: session.user.id },
                        select: { tenantId: true, type: true }
                    });
                    if (user) {
                        (session.user as any).tenantId = user.tenantId;
                        (session.user as any).type = user.type;
                    }
                }

                return session;
            },
            async jwt({ token, user, account }: { token: any; user: any; account: any }) {
                if (user) {
                    token.sub = user.id;
                    token.type = (user as any).type;
                    token.tenantId = (user as any).tenantId;
                    token.isOnboarded = (user as any).isOnboarded;
                    token.accessToken = (user as any).accessToken;
                }
                if (!token.tenantId && token.sub) {
                    try {
                        const dbUser = await prisma.user.findUnique({
                            where: { id: token.sub },
                            select: { tenantId: true, type: true }
                        });
                        if (dbUser?.tenantId) {
                            token.tenantId = dbUser.tenantId;
                            token.type = dbUser.type;
                        }
                    } catch {}
                }
                return token;
            },
            async redirect({ url, baseUrl }: { url: string; baseUrl: string }) {
                if (url.startsWith('/')) return `${baseUrl}${url}`;
                else if (new URL(url).origin === baseUrl) return url;
                return `${baseUrl}/dashboard`;
            },
        },
        session: { strategy: "jwt" },
        secret: process.env.NEXTAUTH_SECRET || process.env.AUTH_SECRET,
        trustHost: true,
    } as any
})
