import { useCallback } from 'react';
import { usePersSDK } from '../providers/PersSDKProvider';
import { useTransactionSigner, OnStatusUpdateFn } from './useTransactionSigner';
import type { 
  TransactionRequestDTO, 
  TransactionRequestResponseDTO, 
  TransactionDTO,
  TransactionPaginationRequestDTO,
  PaginatedResponseDTO,
  TransactionIncludeRelation
} from '@explorins/pers-sdk';
import type { TransactionQueryOptions } from '@explorins/pers-sdk/transaction';

// Re-export for consumers
export type { TransactionQueryOptions } from '@explorins/pers-sdk/transaction';

/**
 * React hook for transaction operations in the PERS SDK
 * 
 * Provides comprehensive transaction management including creation, retrieval, history,
 * and administrative operations. Supports pagination and CSV export functionality.
 * 
 * @returns Transaction hook with methods for transaction management
 * 
 * @example
 * ```typescript
 * function TransactionsComponent() {
 *   const { 
 *     createTransaction, 
 *     getUserTransactionHistory 
 *   } = useTransactions();
 *   
 *   const handleCreateTransaction = async (request) => {
 *     try {
 *       const result = await createTransaction(request);
 *       console.log('Transaction created:', result);
 *       // Handle signature URL if returned
 *     } catch (error) {
 *       console.error('Transaction failed:', error);
 *     }
 *   };
 * 
 *   return (
 *     <div>
 *       <button onClick={() => handleCreateTransaction(transactionRequest)}>
 *         Create Transaction
 *       </button>
 *     </div>
 *   );
 * }
 * ```
 */
export const useTransactions = () => {
  const { sdk, isInitialized, isAuthenticated } = usePersSDK();
  const { signAndSubmitTransactionWithJWT, isSignerAvailable, currentStatus, statusMessage } = useTransactionSigner();

  if (!isAuthenticated && isInitialized) {
    console.warn('SDK not authenticated. Some transaction operations may fail.');
  }

  /**
   * Creates a new transaction in the system
   * 
   * Automatically handles signature URLs by opening them in the device's browser.
   * The transaction may require user approval through external wallet applications.
   * 
   * @param request - Transaction request data including amount, recipient, etc.
   * @returns Promise resolving to transaction response with potential actionable items
   * @throws Error if SDK is not initialized
   * 
   * @example
   * ```typescript
   * const { createTransaction } = useTransactions();
   * const request = {
   *   amount: '100',
   *   recipient: '0x123...',
   *   tokenId: 'token-123'
   * };
   * const result = await createTransaction(request, (status, message) => {
   *   console.log(`Status: ${status} - ${message}`);
   * });
   * console.log('Transaction created:', result);
   * ```
   */
  const createTransaction = useCallback(async (request: TransactionRequestDTO, onStatusUpdate?: OnStatusUpdateFn): Promise<TransactionRequestResponseDTO> => {
    if (!isInitialized || !sdk) {
      throw new Error('SDK not initialized. Call initialize() first.');
    }
    
    try {
      const result = await sdk.transactions.createTransaction(request);
      
      // Check if transaction requires signing (contains actionable authToken)
      // Type assertion needed as TransactionRequestResponseDTO type may not include all dynamic properties
      const txToken = result?.actionable?.authToken;
      if (txToken) {
        
        try {
          if (!isSignerAvailable) {
            console.warn('[useTransactions] Transaction signer not available, skipping automatic signing');
            return result;
          }

          // Automatically sign the transaction using the authToken
          const signingResult = await signAndSubmitTransactionWithJWT(txToken, onStatusUpdate);
          
          if (signingResult.success) {
            console.log('[useTransactions] Transaction signed successfully:', signingResult.transactionHash);
            // Return the original result - the transaction is now signed and will be processed
            return result;
          } else {
            console.error('[useTransactions] Transaction signing failed:', signingResult.error);
            // Don't throw error - return the original result so caller can handle signature URL manually
            return result;
          }
        } catch (signingError) {
          console.error('[useTransactions] Blockchain signing error:', signingError);
          // Don't throw error - return the original result so caller can handle signature URL manually
          return result;
        }
      }
      
      return result;
    } catch (error) {
      console.error('Failed to create transaction:', error);
      throw error;
    }
  }, [sdk, isInitialized, signAndSubmitTransactionWithJWT, isSignerAvailable]);

  /**
   * Retrieves a specific transaction by its ID with optional include relations
   * 
   * @param transactionId - Unique identifier of the transaction
   * @param include - Optional relations to include (sender, recipient, business) for enriched entity data
   * @returns Promise resolving to transaction data or null if not found
   * @throws Error if SDK is not initialized
   * 
   * @example
   * ```typescript
   * const { getTransactionById } = useTransactions();
   * 
   * // Basic retrieval
   * const transaction = await getTransactionById('txn-123');
   * 
   * // With enriched sender/recipient data
   * const enrichedTx = await getTransactionById('txn-123', ['sender', 'recipient', 'business']);
   * console.log('Sender:', enrichedTx?.included?.sender);
   * console.log('Business:', enrichedTx?.included?.engagedBusiness?.displayName);
   * ```
   */
  const getTransactionById = useCallback(async (
    transactionId: string,
    include?: TransactionIncludeRelation[]
  ): Promise<TransactionDTO | null> => {
    if (!isInitialized || !sdk) {
      throw new Error('SDK not initialized. Call initialize() first.');
    }
    
    try {
      const result = await sdk.transactions.getTransactionById(transactionId, include);
      return result;
    } catch (error) {
      console.error('Failed to fetch transaction:', error);
      throw error;
    }
  }, [sdk, isInitialized]);

  /**
   * Retrieves transaction history for the authenticated user with comprehensive filtering
   * 
   * Supports filtering by role, status, type, business, token, and more.
   * Optionally enrich with related entities (sender, recipient, business).
   * 
   * @param options - Query options including filters, pagination, and include relations
   * @returns Promise resolving to paginated array of user's transactions
   * @throws Error if SDK is not initialized
   * 
   * @example
   * ```typescript
   * const { getUserTransactionHistory } = useTransactions();
   * 
   * // Simple: Get all transactions
   * const allTransactions = await getUserTransactionHistory();
   * 
   * // Filter by role (legacy support)
   * const sentTransactions = await getUserTransactionHistory({ role: 'SENDER' });
   * 
   * // Advanced filtering with include relations
   * const filtered = await getUserTransactionHistory({
   *   role: 'SENDER',
   *   status: 'COMPLETED',
   *   engagedBusinessId: 'business-123',
   *   include: ['recipient', 'business'],
   *   page: 1,
   *   limit: 20
   * });
   * 
   * // Access enriched data
   * filtered.data.forEach(tx => {
   *   console.log('Recipient:', tx.included?.recipient);
   *   console.log('Business:', tx.included?.engagedBusiness?.displayName);
   * });
   * ```
   */
  const getUserTransactionHistory = useCallback(async (
    options?: TransactionQueryOptions
  ): Promise<PaginatedResponseDTO<TransactionDTO>> => {
    
    if (!isInitialized || !sdk) {
      throw new Error('SDK not initialized. Call initialize() first.');
    }
    
    try {
      const result = await sdk.transactions.getUserTransactionHistory(options);
      return result;
    } catch (error) {
      console.error('Failed to fetch transaction history:', error);
      throw error;
    }
  }, [sdk, isInitialized]);

  /**
   * Admin: Get paginated transactions with optional include relations
   * 
   * @param params - Pagination and filtering parameters
   * @param include - Optional relations to include for enriched entity data
   * @returns Promise resolving to paginated transaction results
   * @throws Error if SDK is not initialized
   * 
   * @example
   * ```typescript
   * const { getPaginatedTransactions } = useTransactions();
   * 
   * // Basic pagination
   * const result = await getPaginatedTransactions({ page: 1, limit: 50 });
   * 
   * // With include relations
   * const enrichedResult = await getPaginatedTransactions(
   *   { page: 1, limit: 50, sortBy: 'createdAt', sortOrder: 'DESC' },
   *   include: ['sender', 'recipient', 'business']
   * });
   * 
   * enrichedResult.data.forEach(tx => {
   *   console.log('From:', tx.included?.sender);
   *   console.log('To:', tx.included?.recipient);
   * });
   * ```
   */
  const getPaginatedTransactions = useCallback(async (
    options: TransactionPaginationRequestDTO & {
      include?: TransactionIncludeRelation[];
    }
  ): Promise<PaginatedResponseDTO<TransactionDTO>> => {
    if (!isInitialized || !sdk) {
      throw new Error('SDK not initialized. Call initialize() first.');
    }
    
    try {
      const result = await sdk.transactions.getPaginatedTransactions(options);
      return result;
    } catch (error) {
      console.error('Failed to fetch paginated transactions:', error);
      throw error;
    }
  }, [sdk, isInitialized]);

  const exportTransactionsCSV = useCallback(async (): Promise<Blob> => {
    if (!isInitialized || !sdk) {
      throw new Error('SDK not initialized. Call initialize() first.');
    }
    
    try {
      const result = await sdk.transactions.exportTransactionsCSV();
      return result;
    } catch (error) {
      console.error('Failed to export transactions CSV:', error);
      throw error;
    }
  }, [sdk, isInitialized]);

  return {
    createTransaction,
    getTransactionById,
    getUserTransactionHistory,
    getPaginatedTransactions,
    exportTransactionsCSV,
    isAvailable: isInitialized && !!sdk?.transactions,
    // Expose signing status for UI feedback
    signingStatus: currentStatus,
    signingStatusMessage: statusMessage,
  };
};

export type TransactionHook = ReturnType<typeof useTransactions>;