/**
 * Moderation Queue Query Builder
 * 
 * Constructs Supabase queries for fetching and filtering moderation queue items.
 * Handles complex filtering logic, pagination, and entity resolution.
 */

import { SupabaseClient } from '@supabase/supabase-js';
import type {
  EntityFilter,
  StatusFilter,
  QueueTab,
  SortConfig,
} from '@/types/moderation';

/**
 * Query configuration for building submission queries
 */
export interface QueryConfig {
  entityFilter: EntityFilter;
  statusFilter: StatusFilter;
  tab: QueueTab;
  userId: string;
  isAdmin: boolean;
  isSuperuser: boolean;
  currentPage: number;
  pageSize: number;
  sortConfig?: SortConfig;
}

/**
 * Result from fetching submissions
 */
export interface FetchSubmissionsResult {
  submissions: any[];
  totalCount: number;
  error?: Error;
}

/**
 * Build a Supabase query for content submissions based on filters
 * 
 * Applies tab-based filtering (main queue vs archive), entity type filtering,
 * status filtering, and access control (admin vs moderator view).
 * 
 * @param supabase - Supabase client instance
 * @param config - Query configuration
 * @param skipModeratorFilter - Skip the moderator access control filter
 * @returns Configured Supabase query builder
 */
export function buildSubmissionQuery(
  supabase: SupabaseClient,
  config: QueryConfig,
  skipModeratorFilter = false
) {
  const { entityFilter, statusFilter, tab, userId, isAdmin, isSuperuser } = config;

  // Build base query with all needed data + user profiles (eliminate N+1 query)
  let query = supabase
    .from('content_submissions')
    .select(`
      id,
      submission_type,
      status,
      content,
      created_at,
      submitted_at,
      user_id,
      reviewed_at,
      reviewer_id,
      reviewer_notes,
      escalated,
      assigned_to,
      locked_until,
      submitter:profiles!content_submissions_user_id_fkey (
        user_id,
        username,
        display_name,
        avatar_url
      ),
      reviewer:profiles!content_submissions_reviewer_id_fkey (
        user_id,
        username,
        display_name,
        avatar_url
      ),
      submission_items (
        id,
        item_type,
        item_data,
        status
      )
    `);

  // CRITICAL: Multi-level ordering
  // Level 1: Always sort by escalated first (descending) - escalated items always appear at top
  query = query.order('escalated', { ascending: false });

  // Level 2: Apply user-selected sort (if provided)
  if (config.sortConfig) {
    query = query.order(config.sortConfig.field, { 
      ascending: config.sortConfig.direction === 'asc' 
    });
  }

  // Level 3: Tertiary sort by created_at as tiebreaker (if not already primary sort)
  if (!config.sortConfig || config.sortConfig.field !== 'created_at') {
    query = query.order('created_at', { ascending: true });
  }

  // Apply tab-based status filtering
  if (tab === 'mainQueue') {
    // Main queue: pending, flagged, partially_approved submissions
    if (statusFilter === 'all') {
      query = query.in('status', ['pending', 'flagged', 'partially_approved']);
    } else if (statusFilter === 'pending') {
      query = query.in('status', ['pending', 'partially_approved']);
    } else {
      query = query.eq('status', statusFilter);
    }
  } else {
    // Archive: approved or rejected submissions
    if (statusFilter === 'all') {
      query = query.in('status', ['approved', 'rejected']);
    } else {
      query = query.eq('status', statusFilter);
    }
  }

  // Apply entity type filter
  if (entityFilter === 'photos') {
    query = query.eq('submission_type', 'photo');
  } else if (entityFilter === 'submissions') {
    query = query.neq('submission_type', 'photo');
  }
  // 'all' and 'reviews' filters don't add any conditions

  // CRM-style claim filtering: moderators only see unclaimed OR self-assigned submissions
  // Admins see all submissions
  // Note: For non-admin users, moderator filtering is handled by multi-query approach in fetchSubmissions
  if (!isAdmin && !isSuperuser && !skipModeratorFilter) {
    const now = new Date().toISOString();
    // Single filter approach (used by getQueueStats)
    query = query.or(
      `assigned_to.is.null,locked_until.lt.${now},assigned_to.eq.${userId}`
    );
  }

  return query;
}

/**
 * Build a count query with the same filters as the main query
 * 
 * Used for pagination to get total number of items matching the filter criteria.
 * 
 * @param supabase - Supabase client instance
 * @param config - Query configuration
 * @returns Configured count query
 */
export function buildCountQuery(
  supabase: SupabaseClient,
  config: QueryConfig
) {
  const { entityFilter, statusFilter, tab, userId, isAdmin, isSuperuser } = config;

  let countQuery = supabase
    .from('content_submissions')
    .select('*', { count: 'exact', head: true });

  // Apply same filters as main query
  if (tab === 'mainQueue') {
    if (statusFilter === 'all') {
      countQuery = countQuery.in('status', ['pending', 'flagged', 'partially_approved']);
    } else if (statusFilter === 'pending') {
      countQuery = countQuery.in('status', ['pending', 'partially_approved']);
    } else {
      countQuery = countQuery.eq('status', statusFilter);
    }
  } else {
    if (statusFilter === 'all') {
      countQuery = countQuery.in('status', ['approved', 'rejected']);
    } else {
      countQuery = countQuery.eq('status', statusFilter);
    }
  }

  if (entityFilter === 'photos') {
    countQuery = countQuery.eq('submission_type', 'photo');
  } else if (entityFilter === 'submissions') {
    countQuery = countQuery.neq('submission_type', 'photo');
  }

  // Note: Count query not used for non-admin users (multi-query approach handles count)
  if (!isAdmin && !isSuperuser) {
    const now = new Date().toISOString();
    countQuery = countQuery.or(
      `assigned_to.is.null,locked_until.lt.${now},assigned_to.eq.${userId}`
    );
  }

  return countQuery;
}

/**
 * Fetch submissions with pagination and all required data
 * 
 * Executes the query and returns both the submissions and total count.
 * Handles errors gracefully and returns them in the result object.
 * 
 * @param supabase - Supabase client instance
 * @param config - Query configuration
 * @returns Submissions data and total count
 * 
 * @example
 * ```tsx
 * const { submissions, totalCount, error } = await fetchSubmissions(supabase, {
 *   entityFilter: 'all',
 *   statusFilter: 'pending',
 *   tab: 'mainQueue',
 *   userId: user.id,
 *   isAdmin: false,
 *   isSuperuser: false,
 *   currentPage: 1,
 *   pageSize: 25
 * });
 * ```
 */
export async function fetchSubmissions(
  supabase: SupabaseClient,
  config: QueryConfig
): Promise<FetchSubmissionsResult> {
  try {
    const { userId, isAdmin, isSuperuser, currentPage, pageSize } = config;
    
    // For non-admin users, use multi-query approach to avoid complex OR filters
    if (!isAdmin && !isSuperuser) {
      return await fetchSubmissionsMultiQuery(supabase, config);
    }
    
    // Admin path: use single query with count
    const countQuery = buildCountQuery(supabase, config);
    const { count, error: countError } = await countQuery;

    if (countError) {
      throw countError;
    }

    // Build main query with pagination
    const query = buildSubmissionQuery(supabase, config);
    const startIndex = (currentPage - 1) * pageSize;
    const endIndex = startIndex + pageSize - 1;
    const paginatedQuery = query.range(startIndex, endIndex);

    // Execute query
    const { data: submissions, error: submissionsError } = await paginatedQuery;

    if (submissionsError) {
      throw submissionsError;
    }

    // Enrich submissions with type field for UI conditional logic
    const enrichedSubmissions = (submissions || []).map(sub => ({
      ...sub,
      type: 'content_submission' as const,
    }));

    return {
      submissions: enrichedSubmissions,
      totalCount: count || 0,
    };
  } catch (error: unknown) {
    return {
      submissions: [],
      totalCount: 0,
      error: error as Error,
    };
  }
}

/**
 * Fetch submissions using multi-query approach for non-admin users
 * 
 * Executes three separate queries to avoid complex OR filters:
 * 1. Unclaimed items (assigned_to is null)
 * 2. Expired locks (locked_until < now, not assigned to current user)
 * 3. Items assigned to current user
 * 
 * Results are merged, deduplicated, sorted, and paginated.
 */
async function fetchSubmissionsMultiQuery(
  supabase: SupabaseClient,
  config: QueryConfig
): Promise<FetchSubmissionsResult> {
  const { userId, currentPage, pageSize } = config;
  const now = new Date().toISOString();
  
  try {
    // Build three separate queries
    // Query 1: Unclaimed items
    const query1 = buildSubmissionQuery(supabase, config, true).is('assigned_to', null);
    
    // Query 2: Expired locks (not mine)
    const query2 = buildSubmissionQuery(supabase, config, true)
      .not('assigned_to', 'is', null)
      .neq('assigned_to', userId)
      .lt('locked_until', now);
    
    // Query 3: My claimed items
    const query3 = buildSubmissionQuery(supabase, config, true).eq('assigned_to', userId);
    
    // Execute all queries in parallel
    const [result1, result2, result3] = await Promise.all([
      query1,
      query2,
      query3,
    ]);
    
    // Check for errors
    if (result1.error) throw result1.error;
    if (result2.error) throw result2.error;
    if (result3.error) throw result3.error;
    
    // Merge all submissions
    const allSubmissions = [
      ...(result1.data || []),
      ...(result2.data || []),
      ...(result3.data || []),
    ];
    
    // Deduplicate by ID
    const uniqueMap = new Map();
    allSubmissions.forEach(sub => {
      if (!uniqueMap.has(sub.id)) {
        uniqueMap.set(sub.id, sub);
      }
    });
    const uniqueSubmissions = Array.from(uniqueMap.values());
    
    // Apply sorting (same logic as buildSubmissionQuery)
    uniqueSubmissions.sort((a, b) => {
      // Level 1: Escalated first
      if (a.escalated !== b.escalated) {
        return b.escalated ? 1 : -1;
      }
      
      // Level 2: Custom sort (if provided)
      if (config.sortConfig) {
        const field = config.sortConfig.field;
        const ascending = config.sortConfig.direction === 'asc';
        const aVal = a[field];
        const bVal = b[field];
        
        if (aVal !== bVal) {
          if (aVal == null) return 1;
          if (bVal == null) return -1;
          
          const comparison = aVal < bVal ? -1 : 1;
          return ascending ? comparison : -comparison;
        }
      }
      
      // Level 3: Tiebreaker by created_at
      const aTime = new Date(a.created_at).getTime();
      const bTime = new Date(b.created_at).getTime();
      return aTime - bTime;
    });
    
    // Apply pagination
    const totalCount = uniqueSubmissions.length;
    const startIndex = (currentPage - 1) * pageSize;
    const endIndex = startIndex + pageSize;
    const paginatedSubmissions = uniqueSubmissions.slice(startIndex, endIndex);
    
    // Enrich with type field
    const enrichedSubmissions = paginatedSubmissions.map(sub => ({
      ...sub,
      type: 'content_submission' as const,
    }));
    
    return {
      submissions: enrichedSubmissions,
      totalCount,
    };
  } catch (error: unknown) {
    return {
      submissions: [],
      totalCount: 0,
      error: error as Error,
    };
  }
}


/**
 * Check if a submission is locked by another moderator
 * 
 * @param submission - Submission object
 * @param currentUserId - Current user's ID
 * @returns True if locked by another user
 */
export function isLockedByOther(
  submission: any,
  currentUserId: string
): boolean {
  if (!submission.locked_until || !submission.assigned_to) {
    return false;
  }

  const lockExpiry = new Date(submission.locked_until);
  const now = new Date();

  // Lock is expired
  if (lockExpiry < now) {
    return false;
  }

  // Locked by current user
  if (submission.assigned_to === currentUserId) {
    return false;
  }

  // Locked by someone else
  return true;
}

/**
 * Get queue statistics (optimized with aggregation query)
 * 
 * Fetches counts for different submission states to display in the queue dashboard.
 * Uses a single aggregation query instead of fetching all data and filtering client-side.
 * 
 * @param supabase - Supabase client instance
 * @param userId - Current user's ID
 * @param isAdmin - Whether user is admin
 * @param isSuperuser - Whether user is superuser
 * @returns Object with various queue statistics
 */
export async function getQueueStats(
  supabase: SupabaseClient,
  userId: string,
  isAdmin: boolean,
  isSuperuser: boolean
) {
  try {
    // Optimized: Use aggregation directly in database
    let statsQuery = supabase
      .from('content_submissions')
      .select('status, escalated');

    // Apply access control using simple OR filter
    if (!isAdmin && !isSuperuser) {
      const now = new Date().toISOString();
      // Show: unclaimed items OR items with expired locks OR my items
      statsQuery = statsQuery.or(
        `assigned_to.is.null,locked_until.lt.${now},assigned_to.eq.${userId}`
      );
    }

    const { data: submissions, error } = await statsQuery;

    if (error) {
      throw error;
    }

    // Calculate statistics (still done client-side but with minimal data transfer)
    const pending = submissions?.filter(s => s.status === 'pending' || s.status === 'partially_approved').length || 0;
    const flagged = submissions?.filter(s => s.status === 'flagged').length || 0;
    const escalated = submissions?.filter(s => s.escalated).length || 0;
    const total = submissions?.length || 0;

    return {
      pending,
      flagged,
      escalated,
      total,
    };
  } catch (error: unknown) {
    // Error already logged in caller, just return defaults
    return {
      pending: 0,
      flagged: 0,
      escalated: 0,
      total: 0,
    };
  }
}
