import NextAuth from "next-auth";
import Google from "next-auth/providers/google";
import Facebook from "next-auth/providers/facebook";
import Twitter from "next-auth/providers/twitter";
import Credentials from "next-auth/providers/credentials";

export const { handlers, signIn, signOut, auth } = NextAuth({
  providers: [
    // Google OAuth
    Google({
      clientId: process.env.GOOGLE_CLIENT_ID!,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
    }),

    // Facebook OAuth
    Facebook({
      clientId: process.env.FACEBOOK_CLIENT_ID!,
      clientSecret: process.env.FACEBOOK_CLIENT_SECRET!,
    }),

    // Twitter OAuth
    Twitter({
      clientId: process.env.TWITTER_CLIENT_ID!,
      clientSecret: process.env.TWITTER_CLIENT_SECRET!,
    }),

    // Email/Password (Credentials)
    Credentials({
      name: "credentials",
      credentials: {
        email: { label: "Email", type: "email" },
        password: { label: "Password", type: "password" },
        accessToken: { label: "Access Token", type: "text" },
        refreshToken: { label: "Refresh Token", type: "text" },
      },
      async authorize(credentials) {
        // Handle 2FA completion - tokens are passed directly
        if (credentials?.accessToken && credentials?.refreshToken) {
          // Verify the tokens by fetching current user
          const verifyRes = await fetch(
            `${process.env.NEXT_PUBLIC_API_URL}/auth/me`,
            {
              method: "GET",
              headers: {
                "Content-Type": "application/json",
                "Authorization": `Bearer ${credentials.accessToken}`,
              },
            }
          );

          if (verifyRes.ok) {
            const userData = await verifyRes.json();
            if (userData.success) {
              return {
                id: userData.data.id,
                email: userData.data.email,
                name: `${userData.data.firstName || ""} ${userData.data.lastName || ""}`.trim(),
                role: userData.data.role,
                accessToken: credentials.accessToken,
                refreshToken: credentials.refreshToken,
              };
            }
          }

          throw new Error("Invalid authentication tokens");
        }

        // Standard login flow
        const res = await fetch(
          `${process.env.NEXT_PUBLIC_API_URL}/auth/login`,
          {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify({
              email: credentials?.email,
              password: credentials?.password,
            }),
          }
        );

        const data = await res.json();

        // Check if 2FA is required
        if (res.ok && data.data?.requiresTwoFactor) {
          // Return null to indicate 2FA is required
          // The frontend will handle the redirect
          throw new Error("2FA_REQUIRED");
        }

        if (res.ok && data.success) {
          return {
            id: data.data.user.id,
            email: data.data.user.email,
            name: `${data.data.user.firstName || ""} ${data.data.user.lastName || ""}`.trim(),
            role: data.data.user.role,
            accessToken: data.data.accessToken,
            refreshToken: data.data.refreshToken,
          };
        }

        // Throw the actual error message from the backend
        throw new Error(data.message || "Invalid email or password");
      },
    }),
  ],

  pages: {
    signIn: "/login",
    error: "/login",
  },

  callbacks: {
    async signIn({ user, account }) {
      // For OAuth providers, sync with backend
      if (account?.provider === "google" || account?.provider === "facebook" || account?.provider === "twitter") {
        try {
          // Read role and agent type from cookies (set by signup page before OAuth redirect)
          let role: string | undefined;
          let agentTypeId: string | undefined;
          let mode: string | undefined;
          try {
            const { cookies } = await import("next/headers");
            const cookieStore = await cookies();
            role = cookieStore.get("socialAuthRole")?.value;
            agentTypeId = cookieStore.get("socialAuthAgentTypeId")?.value;
            mode = cookieStore.get("socialAuthMode")?.value;
          } catch {
            // Cookie may not be available
          }

          const res = await fetch(
            `${process.env.NEXT_PUBLIC_API_URL}/auth/social`,
            {
              method: "POST",
              headers: { "Content-Type": "application/json" },
              body: JSON.stringify({
                provider: account.provider,
                providerId: account.providerAccountId,
                email: user.email || `${account.providerAccountId}@x.com`,
                name: user.name,
                avatar: user.image,
                role,
                agentTypeId,
                mode: mode || 'signup',
              }),
            }
          );

          const data = await res.json();

          if (res.ok && data.success) {
            (user as any).id = data.data.user.id;
            (user as any).role = data.data.user.role;
            (user as any).accessToken = data.data.accessToken;
            (user as any).refreshToken = data.data.refreshToken;
          } else if (!res.ok) {
            const errorMsg = data?.message || "Social login failed";
            const returnTo = mode === 'signup' ? '/signup' : '/login';
            return `${returnTo}?error=${encodeURIComponent(errorMsg)}`;
          }
        } catch (error) {
          console.error("Social auth sync error:", error);
        }
      }

      return true;
    },

    async jwt({ token, user, trigger, session: updateData }) {
      if (user) {
        token.id = user.id;
        token.name = user.name;
        token.email = user.email;
        token.picture = user.image;
        token.role = (user as any).role;
        token.accessToken = (user as any).accessToken;
        token.refreshToken = (user as any).refreshToken;
        // Store when the token was issued for expiration tracking
        token.accessTokenIssuedAt = Date.now();
      }

      // Handle session updates from client-side updateSession() calls
      if (trigger === "update" && updateData?.user) {
        if (updateData.user.name) token.name = updateData.user.name;
        if (updateData.user.image !== undefined) token.picture = updateData.user.image;
      }

      // Auto-refresh the access token if it's about to expire (refresh 2 minutes before expiry)
      // Backend JWT_ACCESS_EXPIRATION=15m, so refresh at ~13 minutes
      const ACCESS_TOKEN_MAX_AGE = 13 * 60 * 1000; // 13 minutes in ms
      const issuedAt = (token.accessTokenIssuedAt as number) || 0;
      if (token.accessToken && Date.now() - issuedAt > ACCESS_TOKEN_MAX_AGE) {
        try {
          const res = await fetch(
            `${process.env.NEXT_PUBLIC_API_URL}/auth/refresh`,
            {
              method: "POST",
              headers: { "Content-Type": "application/json" },
              body: JSON.stringify({
                refreshToken: token.refreshToken,
              }),
            }
          );

          const data = await res.json();

          if (res.ok && data.success) {
            token.accessToken = data.data.accessToken;
            token.refreshToken = data.data.refreshToken;
            token.accessTokenIssuedAt = Date.now();
          } else {
            // Refresh token is also expired - force re-login
            token.error = "RefreshTokenExpired";
          }
        } catch (error) {
          console.error("Token refresh error:", error);
          token.error = "RefreshTokenError";
        }
      }

      return token;
    },

    async session({ session, token }) {
      if (session.user) {
        (session.user as any).id = token.id;
        session.user.name = token.name as string;
        session.user.email = token.email as string;
        session.user.image = token.picture as string;
        (session.user as any).role = token.role;
        (session.user as any).accessToken = token.accessToken;
        (session.user as any).refreshToken = token.refreshToken;
        (session.user as any).error = token.error;
      }
      return session;
    },
  },

  session: {
    strategy: "jwt",
    maxAge: 7 * 24 * 60 * 60, // 7 days
  },

  // Explicit cookie configuration so we can reliably clear them on logout
  cookies: {
    sessionToken: {
      name: process.env.NODE_ENV === 'production' ? '__Secure-authjs.session-token' : 'authjs.session-token',
      options: {
        httpOnly: true,
        sameSite: 'lax',
        path: '/',
        secure: process.env.NODE_ENV === 'production',
      },
    },
    callbackUrl: {
      name: process.env.NODE_ENV === 'production' ? '__Secure-authjs.callback-url' : 'authjs.callback-url',
      options: {
        sameSite: 'lax',
        path: '/',
        secure: process.env.NODE_ENV === 'production',
      },
    },
    csrfToken: {
      name: process.env.NODE_ENV === 'production' ? '__Host-authjs.csrf-token' : 'authjs.csrf-token',
      options: {
        httpOnly: true,
        sameSite: 'lax',
        path: '/',
        secure: process.env.NODE_ENV === 'production',
      },
    },
  },

  secret: process.env.NEXTAUTH_SECRET,
});
