import { supabase } from '@/integrations/supabase/client';
import { getErrorMessage } from '@/lib/errorHandler';
import { logger } from '@/lib/logger';
import { updateSubmissionItem, type SubmissionItemWithDeps, type DependencyConflict } from './submissionItemsService';

export interface ResolutionResult {
  success: boolean;
  updatedSelections?: Set<string>;
  error?: string;
}

/**
 * Main conflict resolution processor
 */
export async function resolveConflicts(
  conflicts: DependencyConflict[],
  resolutions: Record<string, string>,
  items: SubmissionItemWithDeps[],
  userId: string
): Promise<ResolutionResult> {
  try {
    const updatedSelections = new Set<string>();
    
    for (const conflict of conflicts) {
      const resolution = resolutions[conflict.itemId];
      if (!resolution) {
        return {
          success: false,
          error: `No resolution selected for ${conflict.itemId}`,
        };
      }

      const suggestion = conflict.suggestions.find(s => s.action === resolution);
      if (!suggestion) {
        return {
          success: false,
          error: `Invalid resolution action: ${resolution}`,
        };
      }

      // Process each resolution action
      switch (suggestion.action) {
        case 'link_existing':
          if (!suggestion.entityId) {
            return {
              success: false,
              error: 'Entity ID required for link_existing action',
            };
          }
          await linkToExistingEntity(conflict.itemId, suggestion.entityId);
          updatedSelections.add(conflict.itemId);
          break;

        case 'create_parent':
          const item = items.find(i => i.id === conflict.itemId);
          if (item?.depends_on) {
            updatedSelections.add(item.depends_on);
            updatedSelections.add(conflict.itemId);
          }
          break;

        case 'cascade_reject':
          await cascadeRejectDependents(conflict.itemId, items);
          break;

        case 'escalate':
          const submissionId = items[0]?.submission_id;
          if (submissionId) {
            await escalateForAdminReview(submissionId, `Conflict resolution needed: ${conflict.message}`, userId);
          }
          return {
            success: true,
            updatedSelections: new Set(),
          };

        default:
          return {
            success: false,
            error: `Unknown action: ${suggestion.action}`,
          };
      }
    }

    return {
      success: true,
      updatedSelections,
    };
  } catch (error: unknown) {
    const errorMsg = getErrorMessage(error);
    logger.error('Conflict resolution error', {
      action: 'resolve_conflicts',
      conflictCount: conflicts.length,
      error: errorMsg
    });
    return {
      success: false,
      error: errorMsg,
    };
  }
}

/**
 * Link submission item to existing database entity
 */
async function linkToExistingEntity(itemId: string, entityId: string): Promise<void> {
  await updateSubmissionItem(itemId, {
    approved_entity_id: entityId,
    status: 'approved' as const,
  });
}

/**
 * Cascade reject all dependent items
 */
async function cascadeRejectDependents(
  itemId: string,
  items: SubmissionItemWithDeps[]
): Promise<void> {
  const item = items.find(i => i.id === itemId);
  if (!item?.dependents) return;

  const toReject: string[] = [];
  
  function collectDependents(current: SubmissionItemWithDeps) {
    if (current.dependents) {
      for (const dep of current.dependents) {
        toReject.push(dep.id);
        collectDependents(dep);
      }
    }
  }

  collectDependents(item);

  // Reject all collected dependents
  for (const depId of toReject) {
    await updateSubmissionItem(depId, {
      status: 'rejected' as const,
      rejection_reason: 'Parent dependency was rejected',
    });
  }
}

/**
 * Escalate submission for admin review
 */
async function escalateForAdminReview(
  submissionId: string,
  reason: string,
  userId: string
): Promise<void> {
  const { error } = await supabase
    .from('content_submissions')
    .update({
      status: 'pending' as const,
      escalation_reason: reason,
      escalated_by: userId,
      updated_at: new Date().toISOString(),
    })
    .eq('id', submissionId);

  if (error) {
    throw new Error(`Failed to escalate submission: ${error.message}`);
  }
}

/**
 * Find existing entities that match submission data
 */
export async function findMatchingEntities(
  itemType: string,
  itemData: any
): Promise<Array<{ id: string; name: string; similarity: number }>> {
  const tableName = getTableNameForItemType(itemType);
  if (!tableName) return [];

  try {
    // Query based on table type
    if (tableName === 'companies') {
      const { data, error } = await supabase
        .from('companies')
        .select('id, name')
        .ilike('name', `%${itemData.name}%`)
        .limit(5);

      if (error) throw error;

      return (data || []).map(entity => ({
        id: entity.id,
        name: entity.name,
        similarity: calculateSimilarity(itemData.name, entity.name),
      })).sort((a, b) => b.similarity - a.similarity);
    } else if (tableName === 'parks') {
      const { data, error } = await supabase
        .from('parks')
        .select('id, name')
        .ilike('name', `%${itemData.name}%`)
        .limit(5);

      if (error) throw error;

      return (data || []).map(entity => ({
        id: entity.id,
        name: entity.name,
        similarity: calculateSimilarity(itemData.name, entity.name),
      })).sort((a, b) => b.similarity - a.similarity);
    } else if (tableName === 'rides') {
      const { data, error } = await supabase
        .from('rides')
        .select('id, name')
        .ilike('name', `%${itemData.name}%`)
        .limit(5);

      if (error) throw error;

      return (data || []).map(entity => ({
        id: entity.id,
        name: entity.name,
        similarity: calculateSimilarity(itemData.name, entity.name),
      })).sort((a, b) => b.similarity - a.similarity);
    } else if (tableName === 'ride_models') {
      const { data, error } = await supabase
        .from('ride_models')
        .select('id, name')
        .ilike('name', `%${itemData.name}%`)
        .limit(5);

      if (error) throw error;

      return (data || []).map(entity => ({
        id: entity.id,
        name: entity.name,
        similarity: calculateSimilarity(itemData.name, entity.name),
      })).sort((a, b) => b.similarity - a.similarity);
    }

    return [];
  } catch (error: unknown) {
    const errorMsg = getErrorMessage(error);
    logger.error('Error finding matching entities', {
      action: 'find_matching_entities',
      itemType,
      error: errorMsg
    });
    return [];
  }
}

/**
 * Calculate string similarity (simple implementation)
 */
function calculateSimilarity(str1: string, str2: string): number {
  const s1 = str1.toLowerCase();
  const s2 = str2.toLowerCase();
  
  if (s1 === s2) return 1.0;
  if (s1.includes(s2) || s2.includes(s1)) return 0.8;
  
  // Levenshtein distance approximation
  const maxLen = Math.max(s1.length, s2.length);
  const distance = levenshteinDistance(s1, s2);
  return 1 - (distance / maxLen);
}

function levenshteinDistance(str1: string, str2: string): number {
  const matrix: number[][] = [];

  for (let i = 0; i <= str2.length; i++) {
    matrix[i] = [i];
  }

  for (let j = 0; j <= str1.length; j++) {
    matrix[0][j] = j;
  }

  for (let i = 1; i <= str2.length; i++) {
    for (let j = 1; j <= str1.length; j++) {
      if (str2.charAt(i - 1) === str1.charAt(j - 1)) {
        matrix[i][j] = matrix[i - 1][j - 1];
      } else {
        matrix[i][j] = Math.min(
          matrix[i - 1][j - 1] + 1,
          matrix[i][j - 1] + 1,
          matrix[i - 1][j] + 1
        );
      }
    }
  }

  return matrix[str2.length][str1.length];
}

function getTableNameForItemType(itemType: string): string | null {
  const typeMap: Record<string, string> = {
    park: 'parks',
    ride: 'rides',
    manufacturer: 'companies',
    operator: 'companies',
    designer: 'companies',
    property_owner: 'companies',
    ride_model: 'ride_models',
  };
  return typeMap[itemType] || null;
}
