import { exportJWK, generateDPoPToken } from './bluesky-auth';

// Bluesky API utilities
const DEFAULT_API_URL = 'https://bsky.social/xrpc';

// Create a custom lexicon schema for "im.flushing.right.now"
// This would normally be registered with the AT Protocol
export const FLUSHING_STATUS_NSID = 'im.flushing.right.now';

export interface FlushingRecord {
  $type: typeof FLUSHING_STATUS_NSID;
  text: string;
  emoji: string;
  createdAt: string;
}

// Check if a JWT token is expired
export function isTokenExpired(token: string): boolean {
  try {
    // Extract the payload from the JWT token
    const parts = token.split('.');
    if (parts.length !== 3) {
      console.error('Invalid token format');
      return true; // Assume expired if format is invalid
    }
    
    // Decode the payload
    const payload = JSON.parse(atob(parts[1]));
    
    // Check if the token has an expiration time
    if (!payload.exp) {
      console.warn('Token does not have an expiration time');
      return false; // Can't determine if it's expired
    }
    
    // Check if the token is expired
    const now = Math.floor(Date.now() / 1000);
    const isExpired = payload.exp <= now;
    
    if (isExpired) {
      console.log(`Token expired at ${new Date(payload.exp * 1000).toISOString()}`);
    }
    
    // We also want to proactively refresh tokens that will expire soon (within 5 minutes)
    const expiresInSeconds = payload.exp - now;
    const isExpiringSoon = expiresInSeconds > 0 && expiresInSeconds < 300; // 5 minutes
    
    if (isExpiringSoon) {
      console.log(`Token will expire soon: ${expiresInSeconds} seconds remaining`);
    }
    
    return isExpired || isExpiringSoon;
  } catch (error) {
    console.error('Error checking token expiration:', error);
    return true; // Assume expired if there's an error
  }
}

// Refresh an access token using the refresh token
export async function refreshAccessToken(
  refreshToken: string,
  keyPair: CryptoKeyPair,
  pdsEndpoint: string
): Promise<{ 
  accessToken: string; 
  refreshToken: string;
  dpopNonce?: string;
}> {
  try {
    if (!pdsEndpoint) {
      throw new Error('No PDS endpoint provided for token refresh');
    }
    
    console.log('[TOKEN REFRESH] Refreshing token for PDS:', pdsEndpoint);
    
    // CRITICAL FIX: Token refresh endpoint selection based on PDS type
    let authServer = pdsEndpoint;
    
    // For bsky.network PDSes, use bsky.social
    if (pdsEndpoint.includes('bsky.network')) {
      console.log('[TOKEN REFRESH] Using bsky.social for bsky.network PDS');
      authServer = 'https://bsky.social';
    } else if (pdsEndpoint.includes('bsky.social')) {
      // Already using bsky.social
      console.log('[TOKEN REFRESH] Using bsky.social directly');
    } else {
      // For third-party PDSes, use their own endpoint for token refresh
      console.log('[TOKEN REFRESH] Using third-party PDS\'s own endpoint for token refresh:', pdsEndpoint);
      // Keep authServer as the original PDS endpoint for third-party servers
    }
    
    // Endpoint for token refresh
    const tokenEndpoint = `${authServer}/oauth/token`;
    
    // For third-party PDS, directly get nonce from PDS endpoint
    // This is critical because third-party PDSes need their own specific nonce
    let dpopNonce = null;
    
    // Special handling for third-party PDS token refresh
    if (!authServer.includes('bsky.social') && !authServer.includes('bsky.network')) {
      try {
        // For third-party PDS, use a two-step approach to get the valid nonce:
        console.log('[TOKEN REFRESH] Direct nonce retrieval from third-party PDS');
        
        // Step 1: Send an empty token refresh request to get a nonce error
        // This ensures we get the exact format of nonce the PDS expects
        console.log('[TOKEN REFRESH] Step 1: Sending probe request to get nonce');
        const probeResponse = await fetch(tokenEndpoint, {
          method: 'POST',
          headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
          body: new URLSearchParams({
            'grant_type': 'refresh_token',
            'refresh_token': refreshToken,
            'client_id': 'https://flushes.app/client-metadata.json'
          })
        });
        
        // Get the nonce from the error response
        const probeNonce = probeResponse.headers.get('DPoP-Nonce');
        if (probeNonce) {
          console.log('[TOKEN REFRESH] Got DPoP-Nonce from probe response:', probeNonce);
          dpopNonce = probeNonce;
        } else {
          // Try to parse the response body for a nonce in the error message
          let probeText = '';
          try {
            // First try to get the response as text to avoid consuming the body
            probeText = await probeResponse.text();
            
            // Then try to parse it as JSON
            try {
              const probeData = JSON.parse(probeText);
              if (probeData.error === 'use_dpop_nonce' && probeData.nonce) {
                console.log('[TOKEN REFRESH] Got nonce from error body:', probeData.nonce);
                dpopNonce = probeData.nonce;
              }
            } catch (jsonError) {
              console.warn('[TOKEN REFRESH] Failed to parse probe response as JSON:', jsonError);
            }
          } catch (e) {
            console.warn('[TOKEN REFRESH] Failed to get probe response text:', e);
          }
        }
      } catch (directError) {
        console.warn('[TOKEN REFRESH] Direct nonce retrieval failed:', directError);
      }
    }
    
    // Fall back to standard nonce retrieval methods if direct method failed
    if (!dpopNonce) {
      try {
        // Try server-side nonce retrieval first
        console.log('[TOKEN REFRESH] Getting fresh nonce from server API');
        const nonceResponse = await fetch('/api/auth/nonce', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ pdsEndpoint: authServer }) // Use the correct server
        });
        
        if (nonceResponse.ok) {
          const nonceData = await nonceResponse.json();
          if (nonceData.nonce) {
            dpopNonce = nonceData.nonce;
            console.log('[TOKEN REFRESH] Got fresh nonce from server API:', dpopNonce);
          }
        }
        
        // If server-side retrieval fails, try client-side
        if (!dpopNonce) {
          console.log('[TOKEN REFRESH] Trying HEAD request for nonce');
          const headResponse = await fetch(tokenEndpoint, { method: 'HEAD' });
          dpopNonce = headResponse.headers.get('DPoP-Nonce');
        }
        
        // If still no nonce, try POST probe
        if (!dpopNonce) {
          console.log('[TOKEN REFRESH] Trying POST probe for nonce');
          const probeResponse = await fetch(tokenEndpoint, {
            method: 'POST',
            headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
            body: new URLSearchParams({})  // Empty body to trigger error response with nonce
          });
          dpopNonce = probeResponse.headers.get('DPoP-Nonce');
        }
      } catch (nonceError) {
        console.warn('[TOKEN REFRESH] Failed to get initial nonce:', nonceError);
      }
    }
    
    if (!dpopNonce) {
      console.log('[TOKEN REFRESH] No nonce obtained, proceeding without one');
    } else {
      console.log('[TOKEN REFRESH] Obtained nonce:', dpopNonce);
    }
    
    // Generate DPoP token for the refresh request
    const publicKey = await exportJWK(keyPair.publicKey);
    const dpopToken = await generateDPoPToken(
      keyPair.privateKey,
      publicKey,
      'POST',
      tokenEndpoint,
      dpopNonce || undefined
    );
    
    console.log('[TOKEN REFRESH] Making token refresh request');
    
    // Make the token refresh request
    const response = await fetch(tokenEndpoint, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
        'DPoP': dpopToken
      },
      body: new URLSearchParams({
        'grant_type': 'refresh_token',
        'refresh_token': refreshToken,
        'client_id': 'https://flushes.app/client-metadata.json'
      })
    });
    
    // Handle nonce error explicitly - this is the critical part!
    if (response.status === 401 || response.status === 400) {
      let responseBody;
      try {
        responseBody = await response.json();
      } catch (e) {
        responseBody = {};
      }
      
      // Try to get nonce from multiple sources
      let newNonce = response.headers.get('DPoP-Nonce');
      
      // Also check for nonce in the response body (some PDSes return it there)
      if (!newNonce && responseBody.nonce) {
        newNonce = responseBody.nonce;
        console.log('[TOKEN REFRESH] Found nonce in response body:', newNonce);
      }
      
      // Some servers use DPoP-Nonce header instead of nonce in body
      if (!newNonce && response.headers.get('DPoP-Nonce')) {
        newNonce = response.headers.get('DPoP-Nonce');
        console.log('[TOKEN REFRESH] Found DPoP-Nonce in response headers:', newNonce);
      }
      
      // Check for DPoP nonce error
      const isNonceError = 
        responseBody.error === 'use_dpop_nonce' || 
        responseBody.error === 'invalid_dpop_proof' ||
        (responseBody.error_description && (
          responseBody.error_description.includes('nonce') || 
          responseBody.error_description.includes('DPoP')
        ));
      
      if (isNonceError && newNonce) {
        console.log('[TOKEN REFRESH] Received nonce error, retrying with new nonce:', newNonce);
        
        // Generate new DPoP token with the provided nonce
        const retryDpopToken = await generateDPoPToken(
          keyPair.privateKey,
          publicKey,
          'POST',
          tokenEndpoint,
          newNonce
        );
        
        console.log('[TOKEN REFRESH] Retrying token refresh with new nonce');
        
        // Retry the request with the new nonce
        const retryResponse = await fetch(tokenEndpoint, {
          method: 'POST',
          headers: {
            'Content-Type': 'application/x-www-form-urlencoded',
            'DPoP': retryDpopToken
          },
          body: new URLSearchParams({
            'grant_type': 'refresh_token',
            'refresh_token': refreshToken,
            'client_id': 'https://flushes.app/client-metadata.json'
          })
        });
        
        // Read the retry response body ONLY ONCE and store it
        let retryData;
        let retryErrorMessage = '';
        
        try {
          // Try to parse as JSON first
          retryData = await retryResponse.json();
          retryErrorMessage = JSON.stringify(retryData);
        } catch (e) {
          console.warn('[TOKEN REFRESH] Failed to parse retry response as JSON');
          retryData = {}; // Default to empty object
          retryErrorMessage = 'Non-JSON response';
        }
        
        if (!retryResponse.ok) {
          console.error('[TOKEN REFRESH] Token refresh retry failed:', retryResponse.status, retryErrorMessage);
          throw new Error(`Token refresh retry failed: ${retryResponse.status}, ${retryErrorMessage}`);
        }
        
        console.log('[TOKEN REFRESH] Successfully refreshed token on retry');
        
        // Store the new nonce for future requests
        if (typeof localStorage !== 'undefined') {
          localStorage.setItem('dpopNonce', newNonce);
        }
        
        // Return the new tokens and nonce
        return {
          accessToken: retryData.access_token,
          refreshToken: retryData.refresh_token || refreshToken,
          dpopNonce: newNonce
        };
      }
    }
    
    // Read the response body ONLY ONCE and store it
    let responseData;
    let errorMessage = '';
    
    try {
      // Try to parse as JSON first
      responseData = await response.json();
      errorMessage = JSON.stringify(responseData);
    } catch (e) {
      // If JSON parsing fails, handle as regular text
      console.warn('[TOKEN REFRESH] Failed to parse response as JSON, will use raw response');
      responseData = {}; // Default to empty object
      errorMessage = 'Non-JSON response';
    }
    
    if (!response.ok) {
      console.error('[TOKEN REFRESH] Token refresh failed:', response.status, errorMessage);
      throw new Error(`Token refresh failed: ${response.status}, ${errorMessage}`);
    }
    
    // Get any nonce from the response headers
    const responseNonce = response.headers.get('DPoP-Nonce');
    
    console.log('[TOKEN REFRESH] Successfully refreshed access token');
    
    // Update the nonce in localStorage
    if (responseNonce && typeof localStorage !== 'undefined') {
      localStorage.setItem('dpopNonce', responseNonce);
    }
    
    // Return the new tokens and nonce
    return {
      accessToken: responseData.access_token,
      refreshToken: responseData.refresh_token || refreshToken,
      dpopNonce: responseNonce || dpopNonce
    };
  } catch (error) {
    console.error('[TOKEN REFRESH] Error refreshing access token:', error);
    throw error;
  }
}

// Check if authentication is valid by making a simple request
export async function checkAuth(
  accessToken: string,
  keyPair: CryptoKeyPair,
  did: string,
  dpopNonce: string | null = null,
  pdsEndpoint: string | null = null,
  refreshToken: string | null = null // Add refresh token parameter
): Promise<boolean> {
  try {
    if (!pdsEndpoint) {
      console.error('No PDS endpoint provided for auth check');
      return false;
    }
    
    if (!did) {
      console.error('No DID provided for auth check');
      return false;
    }
    
    // For API calls, use the actual PDS endpoint
    // For API calls, always use the user's actual PDS endpoint
    let authServer = pdsEndpoint;
    
    // Special case for token refresh only (not normal API calls)
    // Only bsky.network PDSes should redirect to bsky.social
    if (pdsEndpoint && pdsEndpoint.includes('bsky.network')) {
      console.log('[AUTH CHECK] Will use bsky.social for OAuth on bsky.network PDS');
      authServer = 'https://bsky.social';
    } else {
      console.log('[AUTH CHECK] Using the actual PDS endpoint for auth:', pdsEndpoint);
    }

    // TEMPORARILY DISABLED TOKEN REFRESH
    // This fixes issues with third-party PDSs
    const tokenExpired = isTokenExpired(accessToken);
    if (tokenExpired) {
      console.log('[AUTH CHECK] Token is expired but refresh is temporarily disabled');
      console.log('[AUTH CHECK] User may need to re-authenticate if operations fail');
      // Skip refresh and continue with current token
    }
    
    console.log('Checking auth with PDS endpoint:', pdsEndpoint);
    
    // For API calls, use the actual PDS endpoint
    const baseUrl = `${pdsEndpoint}/xrpc`;
    
    // First, get the user's handle from their DID using repo.describeRepo
    const describeRepoEndpoint = `${baseUrl}/com.atproto.repo.describeRepo`;
    const describeRepoUrl = `${describeRepoEndpoint}?repo=${encodeURIComponent(did)}`;
    
    console.log(`Checking user identity with: ${describeRepoUrl}`);
    
    // We'll use repo.describeRepo first to get user info
    const url = describeRepoUrl;
    
    // Generate DPoP token with the full URL including query params
    const publicKey = await exportJWK(keyPair.publicKey);
    const dpopToken = await generateDPoPToken(
      keyPair.privateKey,
      publicKey,
      'GET',
      url,
      dpopNonce || undefined,
      accessToken // Pass the access token for ath claim
    );
    
    console.log('Making auth check request to:', url);
    
    // Make the request to check auth
    const response = await fetch(url, {
      method: 'GET',
      headers: {
        'Authorization': `DPoP ${accessToken}`,
        'DPoP': dpopToken
      }
    });
    
    if (response.ok) {
      console.log('Auth check successful!');
      return true;
    }
    
    // Log detailed error information and store the response body text ONCE
    let responseText = '';
    // Define responseBody with appropriate type that includes optional error fields
    let responseBody: { 
      error?: string; 
      error_description?: string; 
      message?: string; 
      [key: string]: any 
    } = {};
    
    try {
      responseText = await response.text();
      console.error('Auth check response:', response.status, response.statusText);
      console.error('Auth check error data:', responseText);
      
      // Try to parse as JSON if it looks like JSON
      if (responseText.trim().startsWith('{')) {
        try {
          responseBody = JSON.parse(responseText);
        } catch (jsonError) {
          console.warn('Error data is not valid JSON, using as text');
        }
      }
    } catch (parseError) {
      console.error('Could not read response body:', parseError);
    }
    
    if (response.status === 401) {
      // We already have the response body from above
      console.log('Handling 401 error in auth check');
      
      const nonce = response.headers.get('DPoP-Nonce');
      if (nonce) {
        console.log('[AUTH CHECK] Got nonce during auth check:', nonce);
        
        // Store the nonce for future use
        if (typeof localStorage !== 'undefined') {
          localStorage.setItem('dpopNonce', nonce);
        }
        
        // Check if this is a nonce error
        if ((responseBody?.error === 'use_dpop_nonce') || 
            (responseBody?.error_description && responseBody.error_description.includes('nonce'))) {
          console.log('[AUTH CHECK] DPoP nonce error detected, retrying with new nonce');
        }
        
        // Try again with the nonce, but prevent infinite recursion
        return checkAuth(accessToken, keyPair, did, nonce, pdsEndpoint, refreshToken);
      }
      
      // If we have a refresh token, try to refresh the access token
      if (refreshToken && !tokenExpired) { // Only try this if we didn't already try above
        console.log('[AUTH CHECK] Auth failed with 401, attempting to refresh token...');
        
        try {
          // Try to refresh the token with enhanced error handling
          // Follow the same server selection logic as in refreshAccessToken
          let refreshAuthServer = pdsEndpoint;
          
          // For bsky.network PDSes, use bsky.social
          if (pdsEndpoint.includes('bsky.network')) {
            console.log('[AUTH CHECK] Will use bsky.social for bsky.network PDS');
            refreshAuthServer = 'https://bsky.social';
          } else if (pdsEndpoint.includes('bsky.social')) {
            // Already using bsky.social
            console.log('[AUTH CHECK] Will use bsky.social directly');
          } else {
            // For third-party PDSes, use their own endpoint
            console.log('[AUTH CHECK] Will use third-party PDS\'s own endpoint:', pdsEndpoint);
            // Keep refreshAuthServer as the original PDS endpoint
            
            // Ensure we update the PDS endpoint everywhere
            if (typeof localStorage !== 'undefined') {
              localStorage.setItem('pdsEndpoint', pdsEndpoint);
              localStorage.setItem('bsky_auth_pdsEndpoint', pdsEndpoint);
            }
          }
          
          const { accessToken: newAccessToken, refreshToken: newRefreshToken, dpopNonce: newNonce } = 
            await refreshAccessToken(refreshToken, keyPair, refreshAuthServer);
          
          // Update tokens in localStorage
          if (typeof localStorage !== 'undefined') {
            localStorage.setItem('accessToken', newAccessToken);
            localStorage.setItem('refreshToken', newRefreshToken);
            if (newNonce) localStorage.setItem('dpopNonce', newNonce);
            
            console.log('[AUTH CHECK] Tokens updated in localStorage during checkAuth');
          }
          
          console.log('[AUTH CHECK] Token refreshed successfully, retrying auth check with new token');
          
          // Return the result of checkAuth with the new token
          return checkAuth(newAccessToken, keyPair, did, newNonce || null, pdsEndpoint, newRefreshToken);
        } catch (refreshError) {
          console.error('[AUTH CHECK] Token refresh failed:', refreshError);
          console.log('[AUTH CHECK] User needs to re-authenticate - session cannot be restored');
        }
      }
    }
    
    console.error('Auth check failed with status:', response.status);
    return false;
  } catch (error) {
    console.error('Error checking auth:', error);
    return false;
  }
}

// Make an authenticated request to the Bluesky API
export async function makeAuthenticatedRequest(
  endpoint: string,
  method: string,
  accessToken: string,
  keyPair: CryptoKeyPair,
  dpopNonce: string | null = null,
  body?: any,
  pdsEndpoint: string | null = null
): Promise<any> {
  // Use the PDS endpoint if provided, otherwise fall back to default
  const baseUrl = pdsEndpoint ? `${pdsEndpoint}/xrpc` : DEFAULT_API_URL;
  const url = `${baseUrl}/${endpoint}`;
  
  console.log(`Making ${method} request to ${url} (PDS: ${pdsEndpoint || 'default'})`);
  
  // If no nonce is provided, try to get one first
  if (!dpopNonce) {
    try {
      // Make a HEAD request to get a nonce
      const headResponse = await fetch(url, {
        method: 'HEAD'
      });
      
      const nonce = headResponse.headers.get('DPoP-Nonce');
      if (nonce) {
        return makeAuthenticatedRequest(endpoint, method, accessToken, keyPair, nonce, body, pdsEndpoint);
      }
    } catch (err) {
      console.warn('Failed to get nonce via HEAD request, continuing without it', err);
    }
  }
  
  // Generate the DPoP token
  const publicKey = await exportJWK(keyPair.publicKey);
  const dpopToken = await generateDPoPToken(
    keyPair.privateKey,
    publicKey,
    method,
    url,
    dpopNonce || undefined
  );
  
  // Set headers
  const headers: HeadersInit = {
    'Authorization': `DPoP ${accessToken}`,
    'DPoP': dpopToken,
    'Content-Type': 'application/json'
  };

  const requestOptions: RequestInit = {
    method,
    headers
  };

  if (body) {
    requestOptions.body = JSON.stringify(body);
  }

  // Make the request
  const response = await fetch(url, requestOptions);
  
  // Handle DPoP nonce errors or other 401 errors
  if (response.status === 401) {
    // Try to parse error response
    let responseBody;
    try {
      responseBody = await response.json();
    } catch (e) {
      responseBody = {};
    }
    
    // Get the nonce from headers if available
    const newDpopNonce = response.headers.get('DPoP-Nonce');
    
    // Check if this is a nonce error
    if (
      (responseBody.error === 'use_dpop_nonce' || 
      (responseBody.error_description && responseBody.error_description.includes('nonce'))) &&
      newDpopNonce
    ) {
      // Store the nonce for future use
      if (typeof localStorage !== 'undefined') {
        console.log('[API REQUEST] Storing new DPoP nonce in localStorage:', newDpopNonce);
        localStorage.setItem('dpopNonce', newDpopNonce);
      }
      
      console.log('[API REQUEST] Retrying request with new nonce:', newDpopNonce);
      return makeAuthenticatedRequest(endpoint, method, accessToken, keyPair, newDpopNonce, body, pdsEndpoint);
    }
    
    // Other 401 error, possibly expired token
    console.error('[API REQUEST] Request failed with 401 unauthorized:', responseBody);
    
    // Include nonce in error message if available
    if (newDpopNonce) {
      console.log('[API REQUEST] 401 response included nonce:', newDpopNonce);
      // Store the nonce even though we're not retrying now
      if (typeof localStorage !== 'undefined') {
        localStorage.setItem('dpopNonce', newDpopNonce);
      }
    }
    
    throw new Error(`API request unauthorized: ${JSON.stringify(responseBody)}`);
  }

  // Handle other errors
  if (!response.ok) {
    let errorText;
    try {
      const errorJson = await response.json();
      errorText = JSON.stringify(errorJson);
    } catch {
      errorText = await response.text();
    }
    throw new Error(`API request failed: ${response.status}, ${errorText}`);
  }

  // Parse JSON response if present
  const contentType = response.headers.get('content-type');
  if (!contentType || !contentType.includes('application/json')) {
    return null;
  }

  const result = await response.json();
  
  // Save any nonce for future requests
  const returnNonce = response.headers.get('DPoP-Nonce');
  if (returnNonce && returnNonce !== dpopNonce) {
    console.log('[API REQUEST] New DPoP nonce received in successful response:', returnNonce);
    
    // Always store the latest nonce for future requests
    if (typeof localStorage !== 'undefined') {
      localStorage.setItem('dpopNonce', returnNonce);
      console.log('[API REQUEST] Updated nonce in localStorage for future requests');
    }
  }
  
  return result;
}

// Get the user profile
export async function getProfile(
  accessToken: string,
  keyPair: CryptoKeyPair,
  dpopNonce: string | null = null,
  handle: string = '', // Optional handle to resolve
  pdsEndpoint: string | null = null
): Promise<any> {
  try {
    // Generate a DPoP token for the profile request
    const publicKey = await exportJWK(keyPair.publicKey);
    
    // Use the PDS endpoint if available
    const baseUrl = pdsEndpoint ? `${pdsEndpoint}/xrpc` : 'https://bsky.social/xrpc';
    
    // Step 1: If we have a DID, we want to get both the user's DID and handle
    let endpoint;
    let isDid = handle && handle.startsWith('did:');
    
    // First try to get the user's handle from the DID using PLC directory
    if (isDid) {
      try {
        const plcResponse = await fetch(`https://plc.directory/${handle}/data`);
        
        if (plcResponse.ok) {
          const plcData = await plcResponse.json();
          if (plcData.alsoKnownAs && plcData.alsoKnownAs.length > 0) {
            const handleUrl = plcData.alsoKnownAs[0];
            if (handleUrl.startsWith('at://')) {
              // We found the handle!
              const userHandle = handleUrl.substring(5); // Remove 'at://'
              console.log(`PLC directory resolved DID ${handle} to handle ${userHandle}`);
              
              // Return it immediately
              return { did: handle, handle: userHandle };
            }
          }
        }
      } catch (plcError) {
        console.warn('Failed to resolve handle from PLC directory:', plcError);
      }
      
      // If we get here, we need to use describeRepo to get user info
      endpoint = `${baseUrl}/com.atproto.repo.describeRepo?repo=${encodeURIComponent(handle)}`;
      console.log(`Using describeRepo for DID ${handle} at ${endpoint}`);
    } 
    // If we have a handle but no DID, we need to resolve the handle to a DID
    else if (handle) {
      endpoint = `${baseUrl}/com.atproto.identity.resolveHandle?handle=${encodeURIComponent(handle)}`;
      console.log(`Using resolveHandle for handle ${handle} at ${endpoint}`);
    }
    // If we have neither, we'll try to get the user's own info
    else {
      // Try to get the user's own repo info - note this only works on some PDS servers
      endpoint = `${baseUrl}/com.atproto.repo.describeRepo`;
      console.log(`Using describeRepo without params at ${endpoint}`);
    }
    
    // Generate the DPoP token with the access token for the ath claim
    const dpopToken = await generateDPoPToken(
      keyPair.privateKey, 
      publicKey, 
      'GET', 
      endpoint, 
      dpopNonce || undefined,
      accessToken // Include access token for ath claim
    );
    
    // Make the request via our proxy API
    const response = await fetch('/api/bluesky/profile', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        accessToken,
        dpopToken,
        handle,  // Include the handle in the request
        pdsEndpoint // Include the PDS endpoint
      })
    });
    
    // Even if the response isn't OK, we'll try to parse it
    const responseData = await response.json();
    
    if (!response.ok) {
      console.error('Profile fetch error:', responseData);
      // Return a basic profile if we got an error
      return { did: responseData.did || 'unknown_did', handle: responseData.handle || 'unknown' };
    }
    
    console.log('Profile data from API:', responseData);
    return responseData;
  } catch (error) {
    console.error('Error resolving handle:', error);
    // If we fail to get the profile, return a basic object to avoid breaking the flow
    // The user can still use the app and we'll use the DID as the identifier
    return { handle: 'unknown' };
  }
}

// Create a flushing status record
export async function createFlushingStatus(
  accessToken: string,
  keyPair: CryptoKeyPair,
  did: string,
  text: string,
  emoji: string,
  dpopNonce: string | null = null,
  pdsEndpoint: string | null = null,
  retryCount: number = 0, // Add retry counter
  refreshToken: string | null = null // Add refresh token parameter
): Promise<any> {
  // Safety check: prevent infinite recursion
  if (retryCount >= 3) {
    throw new Error('Maximum retry attempts reached. Could not create status after 3 attempts.');
  }
  
  console.log(`Creating flush status (attempt ${retryCount + 1}) for PDS: ${pdsEndpoint}`);
  
  try {
    // Validate inputs
    if (!accessToken) throw new Error('Access token is required');
    if (!did) throw new Error('DID is required');
    if (!emoji) throw new Error('Emoji is required');
    
    // Format text to ensure it starts with "is"
    let statusText = text ? text.trim() : '';
    
    // If text is empty, use default "is flushing"
    if (!statusText) {
      statusText = "is flushing";
    } 
    // If text doesn't start with "is", add it
    else if (!statusText.toLowerCase().startsWith("is ")) {
      statusText = `is ${statusText}`;
    }
    
    // Use the PDS endpoint if available - THIS IS CRITICAL FOR THIRD-PARTY PDSs
    if (!pdsEndpoint) {
      console.error('Missing PDS endpoint. This will likely fail.');
    }
    
    console.log(`Using PDS endpoint for create record: ${pdsEndpoint}`);
    
    const baseUrl = pdsEndpoint ? `${pdsEndpoint}/xrpc` : 'https://bsky.social/xrpc';
    const endpoint = `${baseUrl}/com.atproto.repo.createRecord`;
    
    console.log(`Endpoint for create record: ${endpoint}`);
    
    // Generate a DPoP token for the create request
    const publicKey = await exportJWK(keyPair.publicKey);
    
    // Generate token with appropriate claims for the request
    const dpopToken = await generateDPoPToken(
      keyPair.privateKey, 
      publicKey, 
      'POST', 
      endpoint, 
      dpopNonce || undefined,
      accessToken // Pass the access token for ath claim
    );
    
    console.log(`Sending flush record creation request to API proxy with PDS: ${pdsEndpoint}`);
    
    // Make the request via our proxy API
    const response = await fetch('/api/bluesky/flushing', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        accessToken,
        dpopToken,
        did,
        text: statusText, // Use statusText which includes default if needed
        emoji,
        pdsEndpoint // Include the PDS endpoint
      })
    });
    
    console.log(`Flush API response status: ${response.status}`);
    
    // Handle response
    if (response.ok) {
      const result = await response.json();
      console.log('Flush record created successfully!');
      return result;
    }
    
    let errorData;
    try {
      errorData = await response.json();
      console.error('Error creating flush record:', errorData);
    } catch (e) {
      errorData = { error: 'unknown', status: response.status };
      console.error('Error parsing error response:', e);
    }
    
    // Handle nonce error with retry - THIS IS ESSENTIAL FOR PDS COMMUNICATION
    if (response.status === 401 && errorData.error === 'use_dpop_nonce' && errorData.nonce) {
      // This is normal operation - DPoP requires a nonce exchange
      console.log('Received nonce from server, retrying request with new nonce:', errorData.nonce);
      
      // Retry with the new nonce and increment retry counter
      return createFlushingStatus(
        accessToken,
        keyPair,
        did,
        statusText, // Use statusText which includes default if needed
        emoji,
        errorData.nonce,
        pdsEndpoint,
        retryCount + 1,
        refreshToken // Pass through the refresh token
      );
    }
    
    // TEMPORARILY DISABLE TOKEN REFRESH LOGIC - it's causing issues with third-party PDSes
    // Just throw an error instead of attempting refresh
    if (response.status === 401) {
      console.error('Authentication expired or invalid. Please log out and log in again.');
      throw new Error('Authentication expired. Please log out and log in again.');
    }
    
    // For other errors, throw with more details
    if (errorData.message) {
      throw new Error(`Status creation failed (${response.status}): ${errorData.message}`);
    } else {
      throw new Error(`Status creation failed with status ${response.status}`);
    }
  } catch (error) {
    console.error('Error creating flushing status:', error);
    throw error;
  }
}