import axios from "axios";
import { IOAuthConfig } from "../interface/OAuth.interface";

// function to genrate OAuth url
export const initiateLogin = (
  provider: "google" | "github" | "microsoft" | "okta",
  clientId: string,
  redirectUri: string
): string => {
  const providerUrls = {
    google: `https://accounts.google.com/o/oauth2/v2/auth?client_id=${clientId}&redirect_uri=${redirectUri}&response_type=code&scope=profile email`,
    github: `https://github.com/login/oauth/authorize?client_id=${clientId}`,
    microsoft: `https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=${clientId}&response_type=code&redirect_uri=${redirectUri}&response_mode=query&scope=https://graph.microsoft.com/.default`,
    okta: `${process.env.OKTA_DOMAIN}/v1/authorize?client_id=${clientId}&response_type=code&scope=openid profile email&redirect_uri=${redirectUri}`,
  };

  return providerUrls[provider];
};

//function to handle OAuth callback
export const handleOAuthCallback = async (
  code: string,
  provider: "google" | "github" | "microsoft" | "okta",
  config: IOAuthConfig
): Promise<any> => {
  try {
    if (!code) {
      return { status: 400, message: "Authorization code is missing" };
    }

    // token urls of particular provider and their payloads
    const tokenUrls = {
      google: "https://oauth2.googleapis.com/token",
      github: "https://github.com/login/oauth/access_token",
      microsoft: "https://login.microsoftonline.com/common/oauth2/v2.0/token",
      okta: `${process.env.OKTA_DOMAIN}/oauth/token`,
    };
    const tokenPayloads =
      provider === "google"
        ? {
            code,
            client_id: config.clientId,
            client_secret: config.clientSecret,
            redirect_uri: config.redirectUri,
            grant_type: "authorization_code",
          }
        : provider === "github"
        ? {
            client_id: config.clientId,
            client_secret: config.clientSecret,
            code,
          }
        : provider === "microsoft"
        ? {
            client_id: config.clientId,
            client_secret: config.clientSecret,
            code,
            redirect_uri: config.redirectUri,
            grant_type: "authorization_code",
          }
        : {
            grant_type: "authorization_code",
            code,
            redirect_uri: config.redirectUri,
            client_id: config.clientId,
            client_secret: config.clientSecret,
          };

    // Microsoft-specific header for token exchange
    const tokenHeaders =
      provider === "microsoft"
        ? { "Content-Type": "application/x-www-form-urlencoded" }
        : { Accept: "application/json" };

    //Exchange authorization code for access token
    const { data: tokenData } = await axios.post(
      tokenUrls[provider],
      tokenPayloads,
      {
        headers: tokenHeaders,
      }
    );
    const accessToken = tokenData.access_token;
    if (!accessToken) {
      return { status: 400, message: "Failed to get access token" };
    }

    //user profile url to fetch the particular user
    const userinfoUrls = {
      google: "https://www.googleapis.com/oauth2/v1/userinfo",
      github: "https://api.github.com/user",
      microsoft: "https://graph.microsoft.com/v1.0/me",
      okta: `${process.env.OKTA_DOMAIN}/v1/userinfo`,
    };

    //fetch user profile from OAuth provider
    const { data: profileData } = await axios.get(userinfoUrls[provider], {
      headers: {
        Authorization: `Bearer ${accessToken}`,
      },
    });

    // extract relevant user details
    const userData =
      provider === "google"
        ? {
            providerId: profileData.id,
            name: profileData.name,
            email: profileData.email,
            provider,
          }
        : provider === "github"
        ? {
            providerId: profileData.id,
            username: profileData.login,
            name: profileData.name,
            provider,
          }
        : provider === "microsoft"
        ? {
            providerId: profileData.id,
            name: profileData.displayName,
            email: profileData.mail || profileData.userPrincipalName,
            provider,
          }
        : {
            providerId: profileData.sub,
            name: profileData.name,
            email: profileData.email,
            provider,
          };

    //check if the user exist
    const existingUser = await config.findUserById(userData.providerId);
    if (!existingUser) {
      const newUser = await config.createUser(userData);
      return {
        status: 200,
        message: "User created successfully",
        user: newUser,
      };
    } else {
      return { status: 200, message: "User already exist", user: existingUser };
    }
  } catch (err) {
    return { status: 500, message: `Failed to get loged in to ${provider}` };
  }
};
