/**
 * AsyncStorage Token Storage for React Native Mobile Platforms
 * 
 * Bundler-agnostic AsyncStorage implementation for mobile platforms.
 * 
 * IMPORTANT: Due to bundler conflicts between Rollup (SDK) and Metro (app),
 * the consuming app MUST set global.AsyncStorageModule before using this SDK:
 * 
 * ```javascript
 * // In your app's index.js, BEFORE importing the SDK:
 * import AsyncStorage from '@react-native-async-storage/async-storage';
 * global.AsyncStorageModule = AsyncStorage;
 * ```
 */

import type { TokenStorage } from '@explorins/pers-sdk/core';

// Declare global type for TypeScript
declare global {
  var AsyncStorageModule: any;
}

/**
 * Get AsyncStorage from the global that the app must set.
 * 
 * This bypasses all bundler resolution issues by having the app
 * explicitly provide the AsyncStorage module via a global variable.
 */
function getAsyncStorage(): any {
  // Check if the app has set the global
  if (global.AsyncStorageModule) {
    const module = global.AsyncStorageModule;
    
    // Validate it has the expected methods
    if (typeof module?.getItem === 'function') {
      console.log('[AsyncStorage] Using global.AsyncStorageModule (direct)');
      return module;
    } else if (typeof module?.default?.getItem === 'function') {
      console.log('[AsyncStorage] Using global.AsyncStorageModule.default');
      return module.default;
    }
  }
  
  // Fallback: try require (may not work due to bundler conflicts)
  try {
    // eslint-disable-next-line @typescript-eslint/no-var-requires
    const module = require('@react-native-async-storage/async-storage');
    
    if (typeof module?.default?.getItem === 'function') {
      console.log('[AsyncStorage] Fallback: using require().default');
      return module.default;
    } else if (typeof module?.getItem === 'function') {
      console.log('[AsyncStorage] Fallback: using require() direct');
      return module;
    }
  } catch (e) {
    // Ignore require errors
  }
  
  // If we get here, provide a helpful error
  throw new Error(
    'AsyncStorage not available. Please add this to your app\'s index.js BEFORE importing the SDK:\n\n' +
    '  import AsyncStorage from \'@react-native-async-storage/async-storage\';\n' +
    '  global.AsyncStorageModule = AsyncStorage;\n\n' +
    'This is required due to bundler conflicts between Rollup and Metro.'
  );
}

/**
 * Bundler-agnostic AsyncStorage wrapper
 * Uses global injection to avoid bundler conflicts
 */
class BundlerAgnosticAsyncStorage {
  private storage: any;

  constructor() {
    // Get AsyncStorage at runtime, not from a potentially corrupted static import
    this.storage = getAsyncStorage();

    // Validate that we have the required methods
    const requiredMethods = ['getItem', 'setItem', 'removeItem', 'getAllKeys', 'multiRemove'];
    const missingMethods = requiredMethods.filter(method => typeof this.storage[method] !== 'function');
    
    if (missingMethods.length > 0) {
      throw new Error(
        `AsyncStorage missing required methods: ${missingMethods.join(', ')}. ` +
        'Ensure @react-native-async-storage/async-storage is properly installed and compatible.'
      );
    }
  }

  async getItem(key: string): Promise<string | null> {
    return this.storage.getItem(key);
  }

  async setItem(key: string, value: string): Promise<void> {
    return this.storage.setItem(key, value);
  }

  async removeItem(key: string): Promise<void> {
    return this.storage.removeItem(key);
  }

  async getAllKeys(): Promise<readonly string[]> {
    return this.storage.getAllKeys();
  }

  async multiRemove(keys: string[]): Promise<void> {
    return this.storage.multiRemove(keys);
  }
}

/**
 * AsyncStorage implementation for mobile platforms
 * 
 * This class is only used on mobile platforms (iOS/Android).
 * Web platforms use LocalStorageTokenStorage from core SDK.
 */
export class AsyncStorageTokenStorage implements TokenStorage {
  private keyPrefix: string;
  private asyncStorage: BundlerAgnosticAsyncStorage;

  constructor(keyPrefix: string = 'pers_tokens_') {
    this.keyPrefix = keyPrefix;
    
    try {
      // Initialize bundler-agnostic AsyncStorage wrapper
      // No longer passes the module - it uses runtime require() internally
      this.asyncStorage = new BundlerAgnosticAsyncStorage();
    } catch (error) {
      console.error('[AsyncStorageTokenStorage] Failed to initialize:', error);
      throw new Error(
        'Failed to initialize AsyncStorage. Make sure @react-native-async-storage/async-storage is installed and ' +
        'this code is running on a React Native mobile platform (not web).'
      );
    }
  }

  async set(key: string, value: string): Promise<void> {
    try {
      const fullKey = `${this.keyPrefix}${key}`;
      await this.asyncStorage.setItem(fullKey, value);
      console.log(`[AsyncStorage] Token stored: ${key}`);
    } catch (error) {
      console.error(`[AsyncStorage] Failed to store token ${key}:`, error);
      throw new Error(`Token storage failed: ${error}`);
    }
  }

  async get(key: string): Promise<string | null> {
    try {
      const fullKey = `${this.keyPrefix}${key}`;
      const value = await this.asyncStorage.getItem(fullKey);
      console.log(`[AsyncStorage] Token retrieved: ${key} - ${value ? 'exists' : 'null'}`);
      return value;
    } catch (error) {
      console.error(`[AsyncStorage] Failed to retrieve token ${key}:`, error);
      return null;
    }
  }

  async remove(key: string): Promise<void> {
    try {
      await this.asyncStorage.removeItem(`${this.keyPrefix}${key}`);
    } catch (error) {
      console.error(`Failed to remove token ${key}:`, error);
    }
  }

  async clear(): Promise<void> {
    try {
      const allKeys = await this.asyncStorage.getAllKeys();
      const ourKeys = allKeys.filter(key => key.startsWith(this.keyPrefix));
      
      if (ourKeys.length > 0) {
        console.log(`[AsyncStorage] Clearing ${ourKeys.length} token(s):`, ourKeys);
        await this.asyncStorage.multiRemove(ourKeys);
        console.log('[AsyncStorage] All tokens cleared successfully');
      } else {
        console.log('[AsyncStorage] No tokens to clear');
      }
    } catch (error) {
      console.error('[AsyncStorage] Failed to clear token storage:', error);
    }
  }
}