class MaterialSyncSuppressionMatcher
  def self.match source_kind:,
                 source_uri: nil,
                 drive_path: nil,
                 drive_file_id: nil,
                 source_path: nil,
                 source_file_id: nil
    key = MaterialSyncSuppression.normalize_source_key(source_kind:,
                                                       source_uri:,
                                                       drive_path:,
                                                       drive_file_id:,
                                                       source_path:,
                                                       source_file_id:)
    return nil if key.blank?

    MaterialSyncSuppression.find_by(normalized_source_key: key)
  end

  def self.match_google_drive_candidate drive_file_id:, relative_path:
    normalized_path = validate_relative_path!(relative_path)

    exact = [
      normalize_key('google_drive_file', drive_file_id),
      normalize_key('google_drive_path', normalized_path),
      normalize_key('legacy_drive_path', normalized_path),
    ].compact

    suppression =
        MaterialSyncSuppression.find_by(normalized_source_key: exact)
    return suppression if suppression

    MaterialSyncSuppression
      .where(source_kind: ['google_drive_path_prefix', 'legacy_drive_path_prefix'])
      .where('drive_path = :path OR :path LIKE CONCAT(drive_path, "/%")', path: normalized_path)
      .order(:id)
      .first
  end

  def self.suppressed?(...)
    match(...).present?
  end

  def self.validate_relative_path! relative_path
    raw = relative_path.to_s.delete("\0").tr('\\', '/').strip
    raise ArgumentError, 'relative_path is required' if raw.blank?
    raise ArgumentError, 'relative_path must be relative' if raw.start_with?('/')
    raise ArgumentError, 'relative_path must be relative' if raw.match?(/\A[A-Za-z]:\//)
    if raw.start_with?('My Drive/', 'マイドライブ/')
      raise ArgumentError, 'relative_path must be relative to source folder'
    end
    raise ArgumentError, 'relative_path must not contain //' if raw.include?('//')
    raise ArgumentError, 'relative_path must not end with /' if raw.end_with?('/')

    parts = raw.split('/')
    if parts.any? { |part| part.in?(['.', '..']) }
      raise ArgumentError, 'relative_path must not contain dot segments'
    end

    raw
  end

  def self.normalize_key source_kind, value
    return nil if value.blank?

    MaterialSyncSuppression.normalize_source_key(source_kind:, source_path: value,
                                                 source_file_id: value)
  end
end
