import { ZodError, ZodIssue } from 'zod';

/**
 * Extracts and formats human-readable error messages from ZodError instances.
 *
 * This function processes Zod validation errors and transforms them into
 * user-friendly messages that can be displayed in UI components.
 *
 * @param error - The ZodError instance to extract messages from
 * @returns A formatted string containing all validation error messages
 *
 * @example
 * ```typescript
 * try {
 *   schema.parse(data);
 * } catch (error) {
 *   if (error instanceof ZodError) {
 *     const message = extractZodErrorMessage(error);
 *     // Display message to user
 *   }
 * }
 * ```
 */
export function extractZodErrorMessage(error: ZodError): string {
  if (!error.issues || error.issues.length === 0) {
    return 'Unbekannter Validierungsfehler aufgetreten.';
  }

  const messages = error.issues.map((issue) => formatZodIssue(issue));

  // Remove duplicates and join with line breaks
  const uniqueMessages = Array.from(new Set(messages));

  if (uniqueMessages.length === 1) {
    return uniqueMessages[0];
  }

  return `Es sind ${uniqueMessages.length} Validierungsfehler aufgetreten:\n\n${uniqueMessages.map(msg => `• ${msg}`).join('\n')}`;
}

/**
 * Formats a single ZodIssue into a human-readable message.
 *
 * @param issue - The ZodIssue to format
 * @returns A formatted error message string
 */
function formatZodIssue(issue: ZodIssue): string {
  const fieldPath = formatFieldPath(issue.path);
  const fieldPrefix = fieldPath ? `${fieldPath}: ` : '';

  switch (issue.code) {
    case 'invalid_type':
      return `${fieldPrefix}${formatInvalidTypeMessage(issue)}`;

    case 'too_small':
      return `${fieldPrefix}${formatTooSmallMessage(issue)}`;

    case 'too_big':
      return `${fieldPrefix}${formatTooBigMessage(issue)}`;

    case 'invalid_string':
      return `${fieldPrefix}${formatInvalidStringMessage(issue)}`;

    case 'unrecognized_keys':
      return `${fieldPrefix}Unbekannte Felder: ${issue.keys?.join(', ')}`;

    case 'invalid_union':
      return `${fieldPrefix}Wert entspricht nicht den erwarteten Optionen`;

    case 'invalid_enum_value':
      return `${fieldPrefix}Ungültiger Wert. Erlaubt sind: ${issue.options?.join(', ')}`;

    case 'invalid_arguments':
      return `${fieldPrefix}Ungültige Parameter`;

    case 'invalid_return_type':
      return `${fieldPrefix}Ungültiger Rückgabetyp`;

    case 'invalid_date':
      return `${fieldPrefix}Ungültiges Datum`;

    case 'invalid_literal':
      return `${fieldPrefix}Wert muss exakt '${issue.expected}' sein`;

    case 'custom':
      return `${fieldPrefix}${issue.message || 'Benutzerdefinierte Validierung fehlgeschlagen'}`;

    default:
      return `${fieldPrefix}${issue.message || 'Validierungsfehler'}`;
  }
}

/**
 * Formats a field path array into a human-readable string.
 *
 * @param path - Array of field path segments
 * @returns Formatted path string or empty string if no path
 */
function formatFieldPath(path: (string | number)[]): string {
  if (!path || path.length === 0) {
    return '';
  }

  return path
    .map((segment) => {
      if (typeof segment === 'number') {
        return `[${segment}]`;
      }
      return segment;
    })
    .join(' → ');
}

/**
 * Formats invalid type error messages with German translations.
 */
function formatInvalidTypeMessage(issue: ZodIssue & { expected: string; received: string }): string {
  const typeTranslations: Record<string, string> = {
    string: 'Text',
    number: 'Zahl',
    boolean: 'Ja/Nein-Wert',
    object: 'Objekt',
    array: 'Liste',
    date: 'Datum',
    undefined: 'undefiniert',
    null: 'null',
    bigint: 'große Zahl',
    function: 'Funktion',
    symbol: 'Symbol',
  };

  const expected = typeTranslations[issue.expected] || issue.expected;
  const received = typeTranslations[issue.received] || issue.received;

  return `Erwartet: ${expected}, erhalten: ${received}`;
}

/**
 * Formats "too small" error messages based on the type.
 */
function formatTooSmallMessage(issue: any): string {
  const { type, minimum, inclusive } = issue;
  const operator = inclusive ? 'mindestens' : 'mehr als';

  switch (type) {
    case 'string':
      return `Text muss ${operator} ${minimum} Zeichen lang sein`;
    case 'number':
    case 'bigint':
      return `Wert muss ${operator} ${minimum} sein`;
    case 'array':
      return `Liste muss ${operator} ${minimum} Elemente enthalten`;
    case 'set':
      return `Set muss ${operator} ${minimum} Elemente enthalten`;
    case 'date':
      const minDate = typeof minimum === 'bigint' ? new Date(Number(minimum)) : new Date(minimum);
      return `Datum muss ${operator} ${minDate.toLocaleDateString('de-DE')} sein`;
    default:
      return `Wert ist zu klein (min: ${minimum})`;
  }
}

/**
 * Formats "too big" error messages based on the type.
 */
function formatTooBigMessage(issue: any): string {
  const { type, maximum, inclusive } = issue;
  const operator = inclusive ? 'höchstens' : 'weniger als';

  switch (type) {
    case 'string':
      return `Text darf ${operator} ${maximum} Zeichen lang sein`;
    case 'number':
    case 'bigint':
      return `Wert darf ${operator} ${maximum} sein`;
    case 'array':
      return `Liste darf ${operator} ${maximum} Elemente enthalten`;
    case 'set':
      return `Set darf ${operator} ${maximum} Elemente enthalten`;
    case 'date':
      const maxDate = typeof maximum === 'bigint' ? new Date(Number(maximum)) : new Date(maximum);
      return `Datum darf ${operator} ${maxDate.toLocaleDateString('de-DE')} sein`;
    default:
      return `Wert ist zu groß (max: ${maximum})`;
  }
}

/**
 * Formats invalid string error messages based on validation type.
 */
function formatInvalidStringMessage(issue: any): string {
  let validation = 'unknown';

  if (typeof issue.validation === 'string') {
    validation = issue.validation;
  } else if (typeof issue.validation === 'object' && issue.validation) {
    if ('includes' in issue.validation) {
      validation = 'includes';
    } else if ('startsWith' in issue.validation) {
      validation = 'startsWith';
    } else if ('endsWith' in issue.validation) {
      validation = 'endsWith';
    } else {
      validation = Object.keys(issue.validation)[0] || 'unknown';
    }
  }

  const validationMessages: Record<string, string> = {
    email: 'Ungültige E-Mail-Adresse',
    url: 'Ungültige URL',
    uuid: 'Ungültige UUID',
    cuid: 'Ungültige CUID',
    cuid2: 'Ungültige CUID2',
    ulid: 'Ungültige ULID',
    regex: 'Format entspricht nicht dem erwarteten Muster',
    datetime: 'Ungültiges Datum/Zeit-Format',
    ip: 'Ungültige IP-Adresse',
    emoji: 'Muss ein Emoji sein',
    includes: 'Text muss bestimmte Zeichen enthalten',
    startsWith: 'Text muss mit bestimmten Zeichen beginnen',
    endsWith: 'Text muss mit bestimmten Zeichen enden',
    length: 'Text hat eine ungültige Länge',
  };

  return validationMessages[validation] || `Ungültiges Format (${validation})`;
}