/**
 * Lock Auto-Release Mechanism
 * 
 * Automatically releases submission locks when operations fail, timeout,
 * or are abandoned by moderators. Prevents deadlocks and improves queue flow.
 * 
 * Part of Sacred Pipeline Phase 4: Transaction Resilience
 */

import { supabase } from '@/lib/supabaseClient';
import { logger } from '@/lib/logger';
import { isTimeoutError } from '@/lib/timeoutDetection';
import { toast } from '@/hooks/use-toast';

export interface LockReleaseOptions {
  submissionId: string;
  moderatorId: string;
  reason: 'timeout' | 'error' | 'abandoned' | 'manual';
  error?: unknown;
  silent?: boolean; // Don't show toast notification
}

/**
 * Release a lock on a submission
 */
export async function releaseLock(options: LockReleaseOptions): Promise<boolean> {
  const { submissionId, moderatorId, reason, error, silent = false } = options;

  try {
    // Call Supabase RPC to release lock
    const { error: releaseError } = await supabase.rpc('release_submission_lock', {
      submission_id: submissionId,
      moderator_id: moderatorId,
    });

    if (releaseError) {
      logger.error('Failed to release lock', {
        submissionId,
        moderatorId,
        reason,
        error: releaseError,
      });

      if (!silent) {
        toast({
          title: 'Lock Release Failed',
          description: 'Failed to release submission lock. It will expire automatically.',
          variant: 'destructive',
        });
      }

      return false;
    }

    logger.info('Lock released', {
      submissionId,
      moderatorId,
      reason,
      hasError: !!error,
    });

    if (!silent) {
      const message = getLockReleaseMessage(reason);
      toast({
        title: 'Lock Released',
        description: message,
      });
    }

    return true;
  } catch (err) {
    logger.error('Exception while releasing lock', {
      submissionId,
      moderatorId,
      reason,
      error: err,
    });

    return false;
  }
}

/**
 * Auto-release lock when an operation fails
 * 
 * @param submissionId - Submission ID
 * @param moderatorId - Moderator ID
 * @param error - Error that triggered the release
 */
export async function autoReleaseLockOnError(
  submissionId: string,
  moderatorId: string,
  error: unknown
): Promise<void> {
  const isTimeout = isTimeoutError(error);
  
  logger.warn('Auto-releasing lock due to error', {
    submissionId,
    moderatorId,
    isTimeout,
    error: error instanceof Error ? error.message : String(error),
  });

  await releaseLock({
    submissionId,
    moderatorId,
    reason: isTimeout ? 'timeout' : 'error',
    error,
    silent: false, // Show notification for transparency
  });
}

/**
 * Auto-release lock when moderator abandons review
 * Triggered by navigation away, tab close, or inactivity
 */
export async function autoReleaseLockOnAbandon(
  submissionId: string,
  moderatorId: string
): Promise<void> {
  logger.info('Auto-releasing lock due to abandonment', {
    submissionId,
    moderatorId,
  });

  await releaseLock({
    submissionId,
    moderatorId,
    reason: 'abandoned',
    silent: true, // Silent for better UX
  });
}

/**
 * Setup auto-release on page unload (user navigates away or closes tab)
 */
export function setupAutoReleaseOnUnload(
  submissionId: string,
  moderatorId: string
): () => void {
  const handleUnload = () => {
    // Use sendBeacon for reliable unload requests
    const payload = JSON.stringify({
      submission_id: submissionId,
      moderator_id: moderatorId,
    });

    // Try to call RPC via sendBeacon (more reliable on unload)
    const url = `${import.meta.env.VITE_SUPABASE_URL}/rest/v1/rpc/release_submission_lock`;
    const blob = new Blob([payload], { type: 'application/json' });
    
    navigator.sendBeacon(url, blob);

    logger.info('Scheduled lock release on unload', {
      submissionId,
      moderatorId,
    });
  };

  // Add listeners
  window.addEventListener('beforeunload', handleUnload);
  window.addEventListener('pagehide', handleUnload);

  // Return cleanup function
  return () => {
    window.removeEventListener('beforeunload', handleUnload);
    window.removeEventListener('pagehide', handleUnload);
  };
}

/**
 * Monitor inactivity and auto-release after timeout
 * 
 * @param submissionId - Submission ID
 * @param moderatorId - Moderator ID
 * @param inactivityMinutes - Minutes of inactivity before release (default: 10)
 * @returns Cleanup function
 */
export function setupInactivityAutoRelease(
  submissionId: string,
  moderatorId: string,
  inactivityMinutes: number = 10
): () => void {
  let inactivityTimer: NodeJS.Timeout | null = null;

  const resetTimer = () => {
    if (inactivityTimer) {
      clearTimeout(inactivityTimer);
    }

    inactivityTimer = setTimeout(() => {
      logger.warn('Inactivity timeout - auto-releasing lock', {
        submissionId,
        moderatorId,
        inactivityMinutes,
      });

      autoReleaseLockOnAbandon(submissionId, moderatorId);
    }, inactivityMinutes * 60 * 1000);
  };

  // Track user activity
  const activityEvents = ['mousedown', 'keydown', 'scroll', 'touchstart'];
  activityEvents.forEach(event => {
    window.addEventListener(event, resetTimer, { passive: true });
  });

  // Start timer
  resetTimer();

  // Return cleanup function
  return () => {
    if (inactivityTimer) {
      clearTimeout(inactivityTimer);
    }
    activityEvents.forEach(event => {
      window.removeEventListener(event, resetTimer);
    });
  };
}

/**
 * Get user-friendly lock release message
 */
function getLockReleaseMessage(reason: LockReleaseOptions['reason']): string {
  switch (reason) {
    case 'timeout':
      return 'Lock released due to timeout. The submission is available for other moderators.';
    case 'error':
      return 'Lock released due to an error. You can reclaim it to continue reviewing.';
    case 'abandoned':
      return 'Lock released. The submission is back in the queue.';
    case 'manual':
      return 'Lock released successfully.';
  }
}
