/**
 * Transaction Resilience Hook
 * 
 * Combines timeout detection, lock auto-release, and idempotency lifecycle
 * into a unified hook for moderation transactions.
 * 
 * Part of Sacred Pipeline Phase 4: Transaction Resilience
 */

import { useEffect, useCallback, useRef } from 'react';
import { useAuth } from '@/hooks/useAuth';
import {
  withTimeout,
  isTimeoutError,
  getTimeoutErrorMessage,
  type TimeoutError,
} from '@/lib/timeoutDetection';
import {
  autoReleaseLockOnError,
  setupAutoReleaseOnUnload,
  setupInactivityAutoRelease,
} from '@/lib/moderation/lockAutoRelease';
import {
  generateAndRegisterKey,
  validateAndStartProcessing,
  markKeyCompleted,
  markKeyFailed,
  is409Conflict,
  getRetryAfter,
  sleep,
} from '@/lib/idempotencyHelpers';
import { toast } from '@/hooks/use-toast';
import { logger } from '@/lib/logger';

interface TransactionResilientOptions {
  submissionId: string;
  /** Timeout in milliseconds (default: 30000) */
  timeoutMs?: number;
  /** Enable auto-release on unload (default: true) */
  autoReleaseOnUnload?: boolean;
  /** Enable inactivity auto-release (default: true) */
  autoReleaseOnInactivity?: boolean;
  /** Inactivity timeout in minutes (default: 10) */
  inactivityMinutes?: number;
}

export function useTransactionResilience(options: TransactionResilientOptions) {
  const { submissionId, timeoutMs = 30000, autoReleaseOnUnload = true, autoReleaseOnInactivity = true, inactivityMinutes = 10 } = options;
  const { user } = useAuth();
  const cleanupFnsRef = useRef<Array<() => void>>([]);

  // Setup auto-release mechanisms
  useEffect(() => {
    if (!user?.id) return;

    const cleanupFns: Array<() => void> = [];

    // Setup unload auto-release
    if (autoReleaseOnUnload) {
      const cleanup = setupAutoReleaseOnUnload(submissionId, user.id);
      cleanupFns.push(cleanup);
    }

    // Setup inactivity auto-release
    if (autoReleaseOnInactivity) {
      const cleanup = setupInactivityAutoRelease(submissionId, user.id, inactivityMinutes);
      cleanupFns.push(cleanup);
    }

    cleanupFnsRef.current = cleanupFns;

    // Cleanup on unmount
    return () => {
      cleanupFns.forEach(fn => fn());
    };
  }, [submissionId, user?.id, autoReleaseOnUnload, autoReleaseOnInactivity, inactivityMinutes]);

  /**
   * Execute a transaction with full resilience (timeout, idempotency, auto-release)
   */
  const executeTransaction = useCallback(
    async <T,>(
      action: 'approval' | 'rejection' | 'retry',
      itemIds: string[],
      transactionFn: (idempotencyKey: string) => Promise<T>
    ): Promise<T> => {
      if (!user?.id) {
        throw new Error('User not authenticated');
      }

      // Generate and register idempotency key
      const { key: idempotencyKey } = await generateAndRegisterKey(
        action,
        submissionId,
        itemIds,
        user.id
      );

      logger.info('[TransactionResilience] Starting transaction', {
        action,
        submissionId,
        itemIds,
        idempotencyKey,
      });

      try {
        // Validate key and mark as processing
        const isValid = await validateAndStartProcessing(idempotencyKey);
        
        if (!isValid) {
          throw new Error('Idempotency key validation failed - possible duplicate request');
        }

        // Execute transaction with timeout
        const result = await withTimeout(
          () => transactionFn(idempotencyKey),
          timeoutMs,
          'edge-function'
        );

        // Mark key as completed
        await markKeyCompleted(idempotencyKey);

        logger.info('[TransactionResilience] Transaction completed', {
          action,
          submissionId,
          idempotencyKey,
        });

        return result;
      } catch (error) {
        // Check for timeout
        if (isTimeoutError(error)) {
          const timeoutError = error as TimeoutError;
          const message = getTimeoutErrorMessage(timeoutError);

          logger.error('[TransactionResilience] Transaction timed out', {
            action,
            submissionId,
            idempotencyKey,
            duration: timeoutError.duration,
          });

          // Auto-release lock on timeout
          await autoReleaseLockOnError(submissionId, user.id, error);

          // Mark key as failed
          await markKeyFailed(idempotencyKey, message);

          toast({
            title: 'Transaction Timeout',
            description: message,
            variant: 'destructive',
          });

          throw timeoutError;
        }

        // Check for 409 Conflict (duplicate request)
        if (is409Conflict(error)) {
          const retryAfter = getRetryAfter(error);

          logger.warn('[TransactionResilience] Duplicate request detected', {
            action,
            submissionId,
            idempotencyKey,
            retryAfter,
          });

          toast({
            title: 'Duplicate Request',
            description: `This action is already being processed. Please wait ${retryAfter}s.`,
          });

          // Wait and return (don't auto-release, the other request is handling it)
          await sleep(retryAfter * 1000);
          throw error;
        }

        // Generic error handling
        const errorMessage = error instanceof Error ? error.message : 'Unknown error';

        logger.error('[TransactionResilience] Transaction failed', {
          action,
          submissionId,
          idempotencyKey,
          error: errorMessage,
        });

        // Auto-release lock on error
        await autoReleaseLockOnError(submissionId, user.id, error);

        // Mark key as failed
        await markKeyFailed(idempotencyKey, errorMessage);

        throw error;
      }
    },
    [submissionId, user?.id, timeoutMs]
  );

  return {
    executeTransaction,
  };
}
