import { InteractiveBrowserCredential, useIdentityPlugin } from "@azure/identity";
import { nativeBrokerPlugin } from "@azure/identity-broker";
import * as dotenv from "dotenv";

// Initialize the broker plugin for WAM support
useIdentityPlugin(nativeBrokerPlugin);

dotenv.config();

interface TokenCacheEntry {
  token: string;
  expiresAt: number;
}

// Map to store tokens by clientId + tenantId combination
const tokenCache: Map<string, TokenCacheEntry> = new Map();

// Helper function to create a cache key
function createCacheKey(clientId: string, tenantId: string): string {
  return `${clientId}|${tenantId}`;
}

export async function getAccessToken(clientId: string | undefined, tenantId: string | undefined, scopes: string[] | undefined, useBroker: boolean = true): Promise<string> {
  const now = Date.now();

  // Resolve clientId and tenantId, using environment variables as fallback
  const resolvedClientId = clientId || process.env.AZURE_CLIENT_ID || '';
  const resolvedTenantId = tenantId || process.env.AZURE_TENANT_ID || 'common';

  // Create cache key for this client+tenant combination
  const cacheKey = createCacheKey(resolvedClientId, resolvedTenantId);

  // Check if we have a valid cached token for this combination
  const cachedEntry = tokenCache.get(cacheKey);
  if (cachedEntry && cachedEntry.expiresAt > now) {
    return cachedEntry.token;
  }

  try {
    const credentialOptions: any = {
      clientId: resolvedClientId,
      tenantId: resolvedTenantId,
      loginStyle: "popup"
    };

    // Add broker authentication if requested
    if (useBroker) {
      console.log("Using Windows broker authentication (WAM) for interactive login");
      credentialOptions.brokerOptions = {
        enabled: true,
        parentWindowHandle: new Uint8Array(0), // Empty Uint8Array will use the active window
        useDefaultBrokerAccount: false, // Try default account before falling back to interactive
        legacyEnableMsaPassthrough: true // Set to true if MSA account passthrough is needed
      };
    } else {
      console.log("Using standard interactive browser authentication (WAM disabled)");
    }

    const credential = new InteractiveBrowserCredential(credentialOptions);

    const tokenResponse = await credential.getToken([`${resolvedClientId}/.default`].concat(scopes ? scopes : []));

    if (!tokenResponse || !tokenResponse.token) {
      throw new Error("Failed to acquire Azure DevOps token");
    }

    // Set expiration time (expiresOn is in seconds from epoch)
    const expirationTime = tokenResponse.expiresOnTimestamp;
    const expiresAt = expirationTime - (5 * 60 * 1000); // Token lifetime minus 5 minute safety buffer

    // Store the token in cache using the client+tenant key
    tokenCache.set(cacheKey, {
      token: tokenResponse.token,
      expiresAt: expiresAt
    });

    return tokenResponse.token;
  } catch (error) {
    console.error("Error acquiring token:", error);
    throw new Error("Failed to acquire Azure DevOps access token");
  }
}